Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

补码

复习

  1. 第十二章:了解了有符号数和原码,也看到反码的结果总是差 1

TL;DR

  • 负数的补码 = 反码 + 1
  • 补码可以直接参与加法,正数的补码就是它本身
  • 快速求法:从右往左找到第一个 1,该位及右边不变,左边全部取反
  • 补码只有唯一的零,是现代计算机表示有符号数的标准

正文

还差的那 1

  第十二章里我们发现,用反码算 5 + (-2),结果是 2,离正确答案 3 差 1。而且这个“差 1“很稳定。

  既然每次都差 1,那就干脆在负数的编码里事先加 1

  先用最简单的目标验证:我们希望 2 + (-2) = 02 的反码是 0010,让 -2 的反码 1101 再加 1:

  1101
+ 0001
-------
  1110

  现在算 0010 + 1110

  0010
+ 1110
-------
(1)0000   ← 第 5 位进位溢出,直接丢弃,得到 0000

  正好是 0。成了。

补码的定义

负数的补码 = 反码 + 1

  而正数不需要求补,补码就是它自身。

  • 210 的补码 = 0010
  • -210 的补码 = 1101 + 0001 = 1110

  这个编码直接从算式(2 + (-2) = 0)中推导出来,可以直接参与计算,叫作 补码

快速求补码

  每次都“取反再加一“有点麻烦。观察一下可以发现一个更快的办法:

从右往左找到第一个 1,这个 1 以及它右边的位保持不变,左边的位全部取反。

  • 例子:求 -6 的补码。先写出 6 的二进制 0110。最右边的 1 在右起第二位,该位及其右边的 0 保持不变,左边(含符号位)取反,得到 1010。这就是 -6 的补码。

  原因也不难想:反码加 1 时,从右往左第一个 1 右边的 0 会一路进位;而第一个 1 的位置恰好是进位停止的地方,所以右边的低位不变、左边全部翻转。

一个特殊的数

  按照上面的规律推到 1000 就停住了:它根据规则算出的是自身 1000。再往上 10011010……算出来的结果又会和正数编码撞车。

  也就是说,以 01111000 之间为边界,两边的数互补,相加结果为 1111(再进位即 0)。 用图表示,大概是这种感觉:

  所以 4 位补码能表示的范围是 1000(-8)到 0111(+7)。8 位就是 1000 0000(-128)到 0111 1111(+127)。负数的范围比正数多一个,原因就藏在那个“负零“里。

补码的优点

  补码有几个重要的优点:

  1. 统一了加减法运算

    • 减法可以转换为加上一个负数
    • 负数可以用补码表示
    • 所以只需要加法器就可以完成减法
  2. 避免了正负零的问题

    • 原码中 +0 是 0000 0000,-0 是 1000 0000
    • 补码中只有一个零:0000 0000
  3. 简化了硬件设计

    • 不需要专门的减法电路
    • 可以复用加法器

思考题 1

  请分别写出 -5 的 8 位原码、反码和补码。

思考题 2

  为什么 10002 进制补码-810

思考题 3

  在 8 位补码里,-128 的原码是什么?-128 + 1 的结果是多少?为什么?

小结

知识点

  • 补码 = 反码加一
  • 快速求补码的方法
  • 补码的表示范围
  • 补码的三个优点

参考资料

  1. Wikipedia(zh):补码:补码的详细介绍
  2. Bilibili:计算机怎样计算减法

思考题答案(仅供参考)

思考题 1

  • 5 的 8 位原码:0000 0101
  • -5 的 8 位原码:1000 0101
  • -5 的 8 位反码:1111 1010(符号位不变,数值位取反)
  • -5 的 8 位补码:1111 1011(反码加一)

思考题 2

  • 最重要的一点,如果不让 10002 进制补码-810,则运算会发生错误。
  • 所以也人为规定了这点。
  • 本质上,求负数的编码运用了数学上 的概念。
    • 如时钟, 为 12,一旦到达 12 立即回归原点,所以 12 也是 0。
    • 上述加到溢出的做法,也即取模,而在 4 位有符号二进制码中,除去最高位符号位,只能表示 23=8 个数,所以 为 8。
    • 故人为规定:“正零”(0000)为 0,“负零”(1000)为 -8。
      • 若规定 “负零”(1000)为 8,则 0~8 会有 9 个数,而 -1~-7 只有 7 个数,严重不对称,并且运算会发生错误。

思考题 3

  1. -128 没有原码表示(因为正值 128 超出了 8 位能表示的正数范围)
  2. -128 + 1 = 1000 0000 + 0000 0001 = 1000 0001(-127)
    • 这就是为什么 8 位补码的范围是 [-128, 127]
    • -128 是一个特殊值,它没有对应的原码

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪