Skip to content

阅读 CSAPP 关于算术运算的笔记 ​

整数无符号加法 ​

定义 表示两个 范围内的整数相加,将结果截断为 位,且视为 无符号 整数。正常运算情况下,即 时,;但如果发生了溢出,即 的时候,,相当于自动对于 取模。

溢出检查 ​

对于范围 内的 和 ,执行无符号加法,令 ,当且仅当运算结果 (或 )发生了溢出。

求相反数 ​

考虑 位无符号数的集合,执行运算 。对于每个值 ,必然存在某个值 满足 。这个 就是相反数(逆元)。当 时,对应的 。当 时,,因为 :

整数有符号加法(补码加法) ​

定义 表示两个 范围内的整数相加,将结果截断为 位,且视为 补码 数。

简单地说,当 的结果达到或者超过了 ,就是正溢出,要把结果减去 。如果 的值连 位补码表示的最小整数值()都达不到,就是负溢出,要加上 。

实际上,大多数计算机使用同样的机器指令来执行无符号或有符号加法,因为补码加法和无符号加法有相同的位级表示。所以,计算两个有符号(补码)加法,完全可以先把两个数当成无符号的,执行无符号加法,再将结果当成补码。经过一番推导,得到:。

溢出检测 ​

对于范围 内的 和 ,执行无符号加法,令 :

  • 当且仅当 而 时,发生了正溢出
  • 当且仅当 而 时,发生了负溢出

补码的非(相加等于零的数,不是位取反) ​

考虑两段简单的 C++ 代码:

cpp
int x  = -2147483648;
int y = x + x;
std::cout << y << "\n";
// output result is 0, not -4294967296
cpp
int x  = -2147483648;
int y = -x;
std::cout << y << "\n";
// output result is -2147483648, not 2147483648

也就是说,对于 ( 位补码能表示的最小整数),其补码的非(位取反)是自己本身。也就是指,自己加上自己,结果为 。

其实, 本身补码的反,也是 ,然而由于发生了溢出,所以最后又变成了 自己本身。

而补码表示系统当中,一个数的相反数,相当于补码位取反再加上一。所以,在 C/C++ 语言中,表达式 -x 与 ~x+1 是完全一样的。

整数无符号乘法 ​

由于溢出,无符号整数每一步运算,都相当于对 自然溢出取模。所以:。

整数补码乘法 ​

与整数的补码加法类似,依然是先把两个数当成无符号的,执行无符号乘法,再将结果当成补码:。

两个 位数的乘法,产生结果最大可能需要 位表示。所以不是很容易搞溢出检测,但依然可以。CSAPP 把这个问题当作习题。

乘以常数 ​

CSAPP 指出,编译器会转化为左移和加法的组合。