有符号数与原码
复习
- 第三章:了解了计算机使用二进制(0 和 1)表示所有数据
- 第十一章:设计完成了全加器,并可以串联构成多位加法器
TL;DR
- 加法有了,减法可以转化为“加上一个负数“,关键是怎样表示负数
- 原码:最高位做符号位,其余位是数值的绝对值
- 原码不能直接参与计算,因为符号位和数值位会“打架“
- 反码是第一次补救尝试,但算出来的结果总是差 1
正文
引言
加法可以计算了,减法怎么办?5 - 2 = ?
变化一下,似乎可以发现: 减去一个数,等于加上一个负数。 也即 5 - 2 = 5 + (-2),效果一样。但这个想法已经向前迈进了一大步—— 不用专门制造减法器,可以复用加法器,只需表达负数即可。
现在问题来到: 负数在计算机中该怎么表示 ?
原码
先前所有二进制表示,都默认没有符号:从 0000 表示 0 开始,到 1111 表示 15 结束,全是正数,没有负数的余地。
为了解决负数问题,人们专门抽出最高位(最左位)表示符号,0 为正数,1 为负数。其余位为数值位,和原来一样。
0001表示1,1001表示-1,0111表示7,1111表示-7
需要说明的是,这里不一定需要抽出最高位,抽哪一位都可以,抽出最高位只是一种约定俗成的惯例,而且在后续的电路设计中方便一点。
这种“符号位 + 数值绝对值“的二进制码,叫作 原码 。
原码的问题
原码直观,但问题很大:
问题一:零有两个编码。
0000表示+0,1000表示-0- 可数学里并没有“正零““负零“之分,一个零占了两个编码,白白浪费。
问题二:不能直接参与计算。
0010+1001=1011,换成十进制就是2 + (-1) = (-3),明显错了1010+0001=1011,即(-2) + 1 = (-3),也错了
为什么会错?因为加法器把最高位当成了普通的数值位去进位,可它偏偏是符号位,一进位符号就乱了。
不能直接算,计算机就残废了。我们需要一种 能直接参与计算的有符号数编码 。
第一次尝试:反码
那就先把负数的数值位“反过来“试试:
- 正数的反码:和原码相同
- 负数的反码:符号位保持为 1,数值位按位取反
例子:
210 的原码是0010,反码还是0010-210 的原码是1010,反码是1101(符号位 1 不动,010取反成101)
反码看起来比原码聪明了一点,但它依然不能直接相加。看个例子:
0101 (+5)
+ 1101 (-2 的反码)
-------
(1)0010 = 2,而不是 3
结果是 2,离正确的 3 差了 1。
巧的是,这个“差 1“很稳定:不管怎么算,结果总是差那么 1。既然差的永远只是 1,那事先再补上这 1,不就行了?
这就引出了下一章的主角——补码。
思考题
原码的“符号位“其实也是普通二进制位。加法器在算
0010 + 1001时,它“以为“自己在算什么?为什么会得出1011?
小结
知识点
- 用“加上负数“把减法变成加法
- 有符号数与原码
- 原码的两个毛病:负零、不能直接计算
- 反码:第一次尝试,总是差 1
参考资料
- Wikipedia(zh):有符号数:有符号数的各种编码
- Bilibili:计算机怎样计算减法
思考题答案(仅供参考)
加法器并不知道最高位是“符号位“,它只把 0010 和 1001 当成两个普通的四位二进制数相加,得到 1011(十进制 11)。如果按有符号数去读,1011 又被解读成 -3。可我们真正想要的是 2 - 1 = 1。问题就出在:符号位参与了普通加法,却没被特殊对待。补码的精妙之处,正是让符号位也能“顺便“参与运算而不出错。
协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
封面图
设计师 | 南国微雪