贡献者: lzq; addis
原码即 “未经更改” 的码,是指一个二进制数左边加上符号位后所得到的码,且当二进制数大于 $0$ 时,符号位为 0;二进制数小于 $0$ 时,符号位为 $1$;二进制数等于 $0$ 时,符号位可以为 $0$ 或 $1$(表示 $+0$ 或 $-0$)。
使用 $n$ 位原码表示有符号数时,范围是 $-(2^{n-1}-1)$ 到 $+(2^{n-1}-1)$。当 $n=8$ 时,第一位用于符号位,这个范围就是 $-127\sim +127 $;表示无符号数时,由于不需要考虑数的正负,就不需要用一位来表示符号位,$n$ 位机器数全部用来表示是数值,这时表示数的范围就是 $0\sim 2^{n}-1$。当 $n=8$ 时,这个范围就是 $0\sim 255$。
优点: 简单直观,原码易于人类理解和计算(与真值转换容易)。
缺点:原码不能用无符号的加法器进行运算。例如,数学上,$1+(-1)=0$,但把原码直接进行无符号的加法运算时(即把两个相加的数都视为 $0-255$ 的整数相加):
也就是说:原码的运算,必须将符号位和其他位分开,这就增加了硬件的开销和复杂性。也有人将该符号问题称作正负 $0$ 现象。
我们发现:原码最大的问题就在于一个数加上它的相反数不等于 $0$,于是反码的设计思想就是冲着解决这一点,既然一个负数是一个正数的相反数,那干脆用一个正数按位取反来表示负数。
在反码表示法中,正数和 $0$ 的反码与其原码相同;负数的反码则是将原码(除符号位外)的每一位取反。
缺点: 虽然解决了相反数相加不等于 $0$ 的问题,但是反码不能直接做减法,并且存在多余的负零(eg. 1111_1111)
正数和 $0$ 的补码就是该数字本身再补上最高比特 $0$。负数的补码则是将其绝对值按位取反再加 $1$。
优点: 在实现加法器时,只要一种加法电路就可以处理各种有号数加法,因为减法可以用一个数加上另一个数的补码来表示,因此只要有加法电路及补码电路即可完成各种有号数加法及减法,在电路设计上相当方便。(实际在加法器做减法运算时,只需要让减数通过非门,并让个位的 “进位” 端口从 $0$ 变为 $1$ 即可)
另外,补码系统的 $0$ 就只有一个表示方式,这和反码系统不同(在反码系统中,$0$ 有两种表示方式),因此在判断数字是否为 $0$ 时,只要比较一次即可。
补码的规则看起来很怪,我们可以换一种角度理解:
在设计一个编码时,我们可以把编码后的数围成一个圆(类似一个时钟),我们希望在这个钟表上:
从上述角度看,补码是一种很和谐的编码。
对 $N$ bit 的有符号整数,如果用补码表示负整数,则:
1
当且仅当它是负数。
10 ... 0
。
01 ... 1
。
1 ... 1
。