阅读 CSAPP 关于算术运算的笔记
整数无符号加法
定义 表示两个 范围内的整数相加,将结果截断为 位,且视为 无符号 整数。正常运算情况下,即 时,;但如果发生了溢出,即 的时候,,相当于自动对于 取模。
溢出检查
对于范围 内的 和 ,执行无符号加法,令 ,当且仅当运算结果 (或 )发生了溢出。
求相反数
考虑 位无符号数的集合,执行运算 。对于每个值 ,必然存在某个值 满足 。这个 就是相反数(逆元)。当 时,对应的 。当 时,,因为 :
整数有符号加法(补码加法)
定义 表示两个 范围内的整数相加,将结果截断为 位,且视为 补码 数。
简单地说,当 的结果达到或者超过了 ,就是正溢出,要把结果减去 。如果 的值连 位补码表示的最小整数值()都达不到,就是负溢出,要加上 。
实际上,大多数计算机使用同样的机器指令来执行无符号或有符号加法,因为补码加法和无符号加法有相同的位级表示。所以,计算两个有符号(补码)加法,完全可以先把两个数当成无符号的,执行无符号加法,再将结果当成补码。经过一番推导,得到:。
溢出检测
对于范围 内的 和 ,执行无符号加法,令 :
- 当且仅当 而 时,发生了正溢出
- 当且仅当 而 时,发生了负溢出
补码的非(相加等于零的数,不是位取反)
考虑两段简单的 C++ 代码:
int x = -2147483648;
int y = x + x;
std::cout << y << "\n";
// output result is 0, not -4294967296int x = -2147483648;
int y = -x;
std::cout << y << "\n";
// output result is -2147483648, not 2147483648也就是说,对于 ( 位补码能表示的最小整数),其补码的非(位取反)是自己本身。也就是指,自己加上自己,结果为 。
其实, 本身补码的反,也是 ,然而由于发生了溢出,所以最后又变成了 自己本身。
而补码表示系统当中,一个数的相反数,相当于补码位取反再加上一。所以,在 C/C++ 语言中,表达式 -x 与 ~x+1 是完全一样的。
整数无符号乘法
由于溢出,无符号整数每一步运算,都相当于对 自然溢出取模。所以:。
整数补码乘法
与整数的补码加法类似,依然是先把两个数当成无符号的,执行无符号乘法,再将结果当成补码:。
两个 位数的乘法,产生结果最大可能需要 位表示。所以不是很容易搞溢出检测,但依然可以。CSAPP 把这个问题当作习题。
乘以常数
CSAPP 指出,编译器会转化为左移和加法的组合。