补码回顾

以下均以 8 位补码为例。正数的补码与其普通二进制表示相同;负数的补码可由对应正数按位取反,再加 1得到。例如,5=000001015=00000101,取反得到 1111101011111010,再加 1,便得到 −5-5 的补码 1111101111111011。

nn 位补码的表示范围是 −2n−1∼2n−1−1-2^{n-1}\sim 2^{n-1}-1。因此,8 位补码的范围是 −128∼127-128\sim127:1000000010000000 表示 −128-128,0111111101111111 表示 127127。

补码加减运算

加法

正数和负数可以直接按二进制相加,只保留规定的位数。例如,5+(−3)5+(-3):

  00000101    5
+ 11111101   -3
-----------
1 00000010

舍弃超出 8 位的进位后,得到 0000001000000010,即 22。

减法

减去一个数,等于加上这个数的相反数:A−B=A+(−B)A-B=A+(-B)。例如,5−7=5+(−7)5-7=5+(-7):

  00000101    5
+ 11111001   -7
-----------
  11111110

结果的最高位为 11。将 1111111011111110 取反加 1,得到 0000001000000010,所以结果是 −2-2。

什么是溢出

若真实计算结果超出当前位数的补码表示范围,就发生了有符号溢出。例如,100+50=150100+50=150,超出 8 位补码的上限 127127:

  01100100   100
+ 00110010    50
-----------
  10010110

保留的 8 位是 1001011010010110,按补码解释为负数,与真实结果 150150 不符。这就是溢出。

重点: 判断溢出要看真实结果能否用当前位数表示;截断后的补码仍可解释为某个数,但不能把它当作原运算的正确结果。

三种溢出判断方法

以下用 VV 表示有符号溢出标志:V=0V=0 为未溢出,V=1V=1 为溢出。

方法一:一位符号位

运算 可能溢出的前提 溢出的符号特征
A+BA+B AA、BB 同号 结果与 AA、BB 异号
A−BA-B AA、BB 异号 结果与被减数 AA 异号

加法:同号相加,结果变号则溢出。 例如,上面的 100+50100+50 是两个正数相加,保留的结果却是负数。负数相加也一样:−100+(−50)=−150-100+(-50)=-150 超出范围,8 位运算结果为 0110101001101010,符号变成正数。一正一负相加不会发生有符号溢出。

减法:异号相减,结果与被减数变号则溢出。 例如,100−(−50)=150100-(-50)=150,计算时加上 +50+50,仍得到上面的 1001011010010110:被减数为正,结果却被解释为负。类似地,−100−50=−150-100-50=-150 超出下限,8 位结果被解释为正数。同号相减不会发生有符号溢出。

口诀: 加法同号看变号;减法异号看结果是否与被减数变号。

对加法,设两个加数及结果的符号位分别为 AsA_s、BsB_s、SsS_s,则上述规则还可写成:

V=AsBsSs‾+As‾ Bs‾SsV=A_sB_s\overline{S_s}+\overline{A_s}\,\overline{B_s}S_s

即“负数加负数却得正数”,或“正数加正数却得负数”时,V=1V=1。减法直接按表中“被减数与减数异号,且结果与被减数异号”的规则判断。

方法二:符号位前后的进位

5+(−3)5+(-3) 的计算产生了超出 8 位的进位 11,但保留的结果是正确的 22,没有有符号溢出。

  • 进位(Carry) 关注最高位向外的进位,常用于判断无符号运算。
  • 溢出(Overflow) 在这里指有符号补码的真实结果超出表示范围。

因此,不能只凭最高位有没有进位判断有符号溢出,要比较符号位前后的两次进位。

进行补码加法时,比较进入符号位的进位 CinC_{\mathrm{in}} 与从符号位产生的进位 CoutC_{\mathrm{out}}:

  • 两者相同:没有有符号溢出。
  • 两者不同:发生有符号溢出。

其逻辑式为 V=Cin⊕CoutV=C_{\mathrm{in}}\oplus C_{\mathrm{out}}。例如,100+50100+50 的两次进位分别为 11 和 00,所以溢出;5+(−3)5+(-3) 的两次进位均为 11,所以没有溢出。

减法按固定位数计算 A+B‾+1A+\overline B+1 时,也比较这次运算进入和离开符号位的进位。这个方法与前面的符号判断规则等价。

方法三:双符号位

先将两个 nn 位补码操作数的符号位各复制一位,再用 n+1n+1 位进行运算。观察结果的两个最高位 Ss1Ss2S_{s1}S_{s2}(Ss1S_{s1} 为高位符号位):

Ss1Ss2S_{s1}S_{s2} 结果含义
0000 非负数,无溢出
0101 正溢出
1010 负溢出
1111 负数,无溢出

两个符号位不同即溢出,故 V=Ss1⊕Ss2V=S_{s1}\oplus S_{s2}。例如,8 位补码的 100+50100+50 用双符号位运算,结果为 0 100101100\,10010110,最高两位是 0101,表示相对于原来的 8 位范围发生正溢出。减法同样先在扩展后的位数下转换为加法,再观察结果的两个符号位。