原码表示法、反码表示法、移码表示法、补码表示法

数学中使用 10 进制数,并在数字前面加一个负号表示负数。计算机中采用二进制,需要找到一种表示负数的方法。

原码表示法

最朴素的方法就是原码表示法,类似于数学中数字前面是正号表示正数,是负号则表示负数。原码表示法用最高位作为符号位,符号位是 0 则表示正数,符号位是 1 则表示负数。

例如对于 8 位的原码表示法的数

复制代码
0000,0101

转换为 10 进制是 +5, 正号省略不写,则表示的是 5.

要表示负数 -5,则类似于把正号改成负号那样,把

复制代码
0000,0101

的最高位(最左边是最高位)改成 1,变成

复制代码
1000,0101

这就是原码表示法下的 -5.

这种表示法,对于 8 位二进制位来说,实际上只有 7 位是用来表示数值大小的,因此值域是 [-127, 127] ,其中低 7 位全为 0 时表示 0, 但是此时符号位可以为 0 也可以为 1,也就是用了 2 种 2 进制组合去表示 0 这个数,有点浪费了。

原码表示法的纯小数

对于 8 位的原码表示法的数,把它看成隐含着一个分母,这个分母的值是
2 8 − 1 = 2 7 = 128 2^{8-1} = 2^7 = 128 28−1=27=128

于是值域从原本的 [-127, 127] 变成了

− 127 128 , 127 128 \] \[-\\frac{127}{128}, \\frac{127}{128}\] \[−128127,128127

即相当于每一位的权重发生改变了

  • 想要表示 +0.5,即 + 1 2 +\frac{1}2{} +21 ,就让权重是 2 − 1 2^{-1} 2−1 的位为 1,其他位为 0,并且符号位为 0. 即 0100,0000 .

  • 想要表示 -0.5,即 − 1 2 -\frac{1}2{} −21,就让权重是 2 − 1 2^{-1} 2−1 的位为 1,其他位为 0,并且符号位为 1. 即 1100,0000

或者这样思考:

  • 想要表示 -0.5,符号位是 1,然后因为值实际上是隐含着分母 128 的,所以要写出一个二进制原码,它的值除以 128 后等于 1 2 \frac{1}{2} 21

反码表示法

前面的原码表示法是把最高位当成正负号来用,现在的反码表示法是:

  • 正数就正常写出二进制
  • 如果是负数,先写出它的相反数的二进制,再进行位取反操作。

这种表示法最终的现象也是:

  • 最高位为 0 时表示的是正数。
  • 最高位为 1 时表示的是负数。

但是现在最高位并不再像原码表示法那样具有正负号的含义了,他只是表现出来的现象让它看起来好像是具有像正负号那样的含义。

例如表示 +5 ,把 5 转为二进制:

复制代码
0000,0101

表示 -5 :

先写出它的相反数,即 5 的二进制

复制代码
0000,0101

然后把每一位取反,得到

复制代码
1111,1010

这就是反码表示法下的 -5

全 1 数减去 x, 相当于把 x 按位取反

以 8 位二进制数为例,列一个减法竖式

移码表示法

移码的思想也很朴素。本来二进制数只能表示正数,因为没地方给你添加一个负号来告诉计算机这是负数。除非像原码那样用最高位来模拟正负号。于是有人想出了把值域向下移动一段距离,就得到了表示负数的能力。

例如对于 8 位二进制数,本来值域是 [0, 255] ,如果向下移动 2 8 − 1 = 2 7 = 128 2^{8-1} = 2^7 = 128 28−1=27=128,则值域变成了 [-128, 127]

那怎么用移码表示 -5 呢?

移码表示法最大的问题是 0 点与无符号整型不重合,计算不方便,无法自然地进行无符号整型和有符号整型之间的转换。

下面的补码表示法就可以解决这个问题

补码表示法

补码比较复杂,见
无符号整型通过调整数轴的解释方式得到补码形式的有符号整型