原码、反码、补码

                     

贡献者: lzq

  • 本文处于草稿阶段。

1. 原码(True form)

   原码即 “未经更改” 的码,是指一个二进制数左边加上符号位后所得到的码,且当二进制数大于 0 时,符号位为 0;二进制数小于 0 时,符号位为 1;二进制数等于 0 时,符号位可以为 0 或 1(+0/-0)。

   使用 n 位原码表示有符号数时,范围是 $-(2^{n-1}-1)\sim +(2^{n-1}-1)$。当 n=8 时,这个范围就是 $-127\sim +127 $;表示无符号数时,由于不需要考虑数的正负,就不需要用一位来表示符号位,n 位机器数全部用来表示是数值,这时表示数的范围就是 $0\sim 2^{n}-1$。当 $n=8$ 时,这个范围就是 $0\sim 255$。

   优点: 简单直观,原码易于人类理解和计算(与真值转换容易)。

   缺点:原码不能直接被用于运算。 对于加法运算,例如,数学上,1+(-1)=0,但用原码进行运算时:

例 1 

   00000001+10000001=10000010

   该结果对应数值为-2。显然出错了; 对于减法运算,原码减法需要先将减数取反加 1,才能得到正确的数学结果。

   也就是说:原码的运算,必须将符号位和其他位分开,这就增加了硬件的开销和复杂性。(也有人将该符号问题称作正负 0 现象)

2. 反码(1's complement)

   我们发现: 原码最大的问题就在于一个数加上它的相反数不等于 0,于是反码的设计思想就是冲着解决这一点,既然一个负数是一个正数的相反数,那干脆用一个正数按位取反来表示负数。

   在反码表示法中,正数和 0 的反码与其原码相同;负数的反码则是将原码(除符号位外)的每一位取反。

   缺点: 虽然解决了相反数想加不等于 0 的问题,但是反码不能直接做减法,并且存在多余的负零(eg. 1111_1111)

例 2 

   0001+1110=1111,1+(-1)=-0;

   1110+1100=1010,(-1)+(-3)=-5。

3. 补码(2's complement)

   正数和 0 的补码就是该数字本身再补上最高比特 0。负数的补码则是将其绝对值按位取反再加 1。

   优点: 在实现加法器时,只要一种加法电路就可以处理各种有号数加法,因为减法可以用一个数加上另一个数的补码来表示,因此只要有加法电路及补码电路即可完成各种有号数加法及减法,在电路设计上相当方便。(实际在加法器做减法运算时,只需要让减数通过非门,并让个位的 “进位” 端口从 0 变为 1 即可)

   另外,补码系统的 0 就只有一个表示方式,这和反码系统不同(在反码系统中,0 有两种表示方式),因此在判断数字是否为 0 时,只要比较一次即可。

4. 补码的设计

   补码的规则看起来很怪,我们可以换一种角度理解:

   在设计一个编码时,我们可以把编码后的数围成一个圆(类似一个时钟),我们希望在这个钟表上:

  1. 无冲突,每个数值的位置都是独一无二,有唯一的 0。
  2. 连续性,每次运算(+1)相当于时钟顺时针移动一个单位,尤其是从最大的正数加 1 会 “溢出” 到最小的负数,这种看似异常的行为实际上提供了一个连续且循环的数值范围,使得算术运算能够在这个编码系统中顺畅地进行。

   从上述角度看,补码是一种很和谐的编码。

                     

© 小时科技 保留一切权利