补码回顾
以下均以 8 位补码为例。正数的补码与其普通二进制表示相同;负数的补码可由对应正数按位取反,再加 1得到。例如,,取反得到 ,再加 1,便得到 的补码 。
位补码的表示范围是 。因此,8 位补码的范围是 : 表示 , 表示 。
补码加减运算
加法
正数和负数可以直接按二进制相加,只保留规定的位数。例如,:
00000101 5
+ 11111101 -3
-----------
1 00000010
舍弃超出 8 位的进位后,得到 ,即 。
减法
减去一个数,等于加上这个数的相反数:。例如,:
00000101 5
+ 11111001 -7
-----------
11111110
结果的最高位为 。将 取反加 1,得到 ,所以结果是 。
什么是溢出
若真实计算结果超出当前位数的补码表示范围,就发生了有符号溢出。例如,,超出 8 位补码的上限 :
01100100 100
+ 00110010 50
-----------
10010110
保留的 8 位是 ,按补码解释为负数,与真实结果 不符。这就是溢出。
重点: 判断溢出要看真实结果能否用当前位数表示;截断后的补码仍可解释为某个数,但不能把它当作原运算的正确结果。
三种溢出判断方法
以下用 表示有符号溢出标志: 为未溢出, 为溢出。
方法一:一位符号位
| 运算 | 可能溢出的前提 | 溢出的符号特征 |
|---|---|---|
| 、 同号 | 结果与 、 异号 | |
| 、 异号 | 结果与被减数 异号 |
加法:同号相加,结果变号则溢出。 例如,上面的 是两个正数相加,保留的结果却是负数。负数相加也一样: 超出范围,8 位运算结果为 ,符号变成正数。一正一负相加不会发生有符号溢出。
减法:异号相减,结果与被减数变号则溢出。 例如,,计算时加上 ,仍得到上面的 :被减数为正,结果却被解释为负。类似地, 超出下限,8 位结果被解释为正数。同号相减不会发生有符号溢出。
口诀: 加法同号看变号;减法异号看结果是否与被减数变号。
对加法,设两个加数及结果的符号位分别为 、、,则上述规则还可写成:
即“负数加负数却得正数”,或“正数加正数却得负数”时,。减法直接按表中“被减数与减数异号,且结果与被减数异号”的规则判断。
方法二:符号位前后的进位
的计算产生了超出 8 位的进位 ,但保留的结果是正确的 ,没有有符号溢出。
- 进位(Carry) 关注最高位向外的进位,常用于判断无符号运算。
- 溢出(Overflow) 在这里指有符号补码的真实结果超出表示范围。
因此,不能只凭最高位有没有进位判断有符号溢出,要比较符号位前后的两次进位。
进行补码加法时,比较进入符号位的进位 与从符号位产生的进位 :
- 两者相同:没有有符号溢出。
- 两者不同:发生有符号溢出。
其逻辑式为 。例如, 的两次进位分别为 和 ,所以溢出; 的两次进位均为 ,所以没有溢出。
减法按固定位数计算 时,也比较这次运算进入和离开符号位的进位。这个方法与前面的符号判断规则等价。
方法三:双符号位
先将两个 位补码操作数的符号位各复制一位,再用 位进行运算。观察结果的两个最高位 ( 为高位符号位):
| 结果含义 | |
|---|---|
| 非负数,无溢出 | |
| 正溢出 | |
| 负溢出 | |
| 负数,无溢出 |
两个符号位不同即溢出,故 。例如,8 位补码的 用双符号位运算,结果为 ,最高两位是 ,表示相对于原来的 8 位范围发生正溢出。减法同样先在扩展后的位数下转换为加法,再观察结果的两个符号位。