原码、反码、补码的理解
概念
机器数、真值
- 机器数
一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用机器数的最高位存放符号,正数为0,负数为1。
比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是0000 0011。如果是 -3 ,就是 100 00011 。
那么,这里的 0000 0011 和 1000 0011 就是机器数。
- 真值
因为第一位是符号位,所以机器数的形式值就不等于真正的数值。
例如上面的有符号数 1000 0011,其最高位1代表负,其真正数值是 -3,而不是形式值131(1000 0011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1
原码、反码、补码
原码、反码、补码是机器存储一个具体数字的编码方式。机器数包含了原码、反码、补码的表示形式。
- 原码
原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值。比如:如果是8位二进制:
[+1]原= 0000 0001
[-1]原= 1000 0001
第一位是符号位,因为第一位是符号位,所以8位二进制数的取值范围就是:(即第一位不表示值,只表示正负。)
[1111 1111 , 0111 1111]
即
[-127 , 127]
- 反码
反码的表示方法是:
正数的反码是其本身;
负数的反码是在其原码的基础上,符号位不变,其余各个位取反。
[+1] = [0000 0001]原= [0000 0001]反
[-1] = [1000 0001]原= [1111 1110]反
可见如果一个反码表示的是负数,人脑无法直观的看出来它的数值。通常要将其转换成原码再计算。
反码表示在计算机中往往作为数码变换的中间环节。
- 补码
补码的表示方法是:
正数的补码就是其本身;
负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1。(也即在反码的基础上+1)
[+1] = [0000 0001]原= [0000 0001]反= [0000 0001]补
[-1] = [1000 0001]原= [1111 1110]反= [1111 1111]补
对于负数,补码表示方式也是人脑无法直观看出其数值的。通常也需要转换成原码再计算其数值。
为什么用反码和补码
计算机辨别”符号位”显然会让计算机的基础电路设计变得十分复杂,所以要把对于负数的减法运算转成加法运算。
将钟表想象成是一个1位的12进制数。例如钟表上的时间为6点,如果我们希望将时间设置为4点,那么我们可以将钟表往回拨2个小时,即“-2”,或者我们可以将钟表往前拨10个小时,即“+10”
- 往回拨2个小时:6 - 2 = 4
- 往前拨10个小时:(6 + 10)mod 12 = 4
这样就将减法计算转成了加法计算。
类似钟表,计算机中的数值也是有一定范围的,所以同样可以将计算机中的减法运算改为加法运算,即将真值为负的机器数转为补码形式再做加法,实际上是将负数转换成了这个它的同余数(概念自行百度)。
补码举例:
2-1 = 2+(-1) = [0000 0010]原+ [1000 0001]原= [0000 0010]补 + [1111 1111]补
如果把[1111 1111]当成原码,去除符号位,则[0111 1111]原 = 127
相当于
2-1 ≡ 2+127 (mod 128)
到底什么是补码
所以到底什么是补码?
其实负数的补码等于反码+1只是补码的求法,而不是补码的定义,很多人以为求补码就要先求反码,其实并不是,那些计算机学家并不会心血来潮的把反码+1就定义为补码,只不过补码正好就等于反码+1而已。
其实负数的补码,是能够和其相反数相加通过溢出从而使计算机内计算结果变为0的二进制码。这是补码设计的初衷,具体目标就是让1+(-1)=0,这利用原码是无法得到的:
0001(1) + 1001(-1) = 1010(-2)
而在补码中:
0001(1补) + 1111(-1补) = 10000(1溢出)
所以对于一个n位的负数-X,有如下关系
X补 + (-X)补 = 100…0(n个0) = 2^n^
假设寄存器是n位的,那么-X的补码应该是2^n^ - X的二进制编码
例如:
X = - 0b11(-3) ,四比特表示原码 = 1011(11),对应反码为 = 1100(12),补码为1101(13);
如果寄存器4位,-3对应的补码二进制数为13,刚好是2^4^-3
正十进制数X补码等于其本身,n位寄存器下-X的补码等于2^n^-X对应的二进制编码。
已知补码如何求原码
二进制
补码的补码就是原码
十进制
n位寄存器下-X的补码等于2^n^-X对应的二进制编码。
(1)十进制的情况下,如果给的补码是无符号数2^n^-X,那么原码即(2^n^-X) - 2^n^ = -X:
例如前面-3补码无符号数是13,对应的原码就是13-2^4^=-3
(2)十进制的情况下,如果给的补码是有符号数-Y,对应的无符号数就是2^n-1^ + Y,那么原码就是(2^n-1^ + Y)- 2^n^=Y-2^n-1^:
例如前面-3补码有符号数是-5,对应的原码就是5-2^3^ = -3