本文采用4位二进制数的例子,从表象对原码反码补码进行探究,旨在说明为什么计算机底层要用补码表示数字以及用补码表示数字的优点,不涉及任何数学原理。
4位二进制数的原码表示:
+0 |
+1 |
+2 |
+3 |
+4 |
+5 |
+6 |
+7 |
0000 |
0001 |
0010 |
0011 |
0100 |
0101 |
0110 |
0111 |
-0 |
-1 |
-2 |
-3 |
-4 |
-5 |
-6 |
-7 |
1000 |
1001 |
1010 |
1011 |
1100 |
1101 |
1110 |
1111 |
- 4位二进制数有16中不同的编码方式,可以对应16个不同的二进制数。为了表示正负,把最高位作为符号位,0正1负。所以采用这种方式表示的10进制数为(-7,-0)∪(+0,+7)。
- 虽然可以表示这16个数了,但是仍存在计算问题,我们希望在计算机中只进行加法运算,并且硬件在计算时不用判断符号位。现在我们尝试一下能否实现:(+1)-(+2)=(+1)+(-2)=0001+1010=1011=(-3),显然这个等式是错误的。因此,如果要正确计算,还需要制定一套比较复杂的运算规则,这会加大计算机硬件的设计复杂度。
4位二进制数的反码表示:
+0 |
+1 |
+2 |
+3 |
+4 |
+5 |
+6 |
+7 |
0000 |
0001 |
0010 |
0011 |
0100 |
0101 |
0110 |
0111 |
-0 |
-1 |
-2 |
-3 |
-4 |
-5 |
-6 |
-7 |
1111 |
1110 |
1101 |
1100 |
1011 |
1010 |
1001 |
1000 |
- 解决的办法是运用某些数学原理(限于脑力与时间,这里不做深究)将负数的表示进行重新编码,这里并不会打扰到之前已经编好的正数的编码。可以看到,这里只相当于用原来-7的编码表示-0,-6的编码表示-1……
- 这样就解决了运算问题,还是上面的例子:(+1)-(+2)=(+1)+(-2)=0001+1101=1110=(-1),得到了正确的结果。在这次计算时,硬件只进行了加法运算,并且硬件在处理二进制时也没有考虑符号位,但仍得到了正确的结果。
- 虽然看似已经解决了计算问题,但是仍存在一个缺点:+0=0000,(+0)+(+1)+(-1)=0000+0001+1110=1111=(-0)。我们不需要+0和-0这两个0。
4位二进制数的补码表示:
+0 |
+1 |
+2 |
+3 |
+4 |
+5 |
+6 |
+7 |
0000 |
0001 |
0010 |
0011 |
0100 |
0101 |
0110 |
0111 |
-0 |
-1 |
-2 |
-3 |
-4 |
-5 |
-6 |
-7 |
-8 |
0000 |
1111 |
1110 |
1101 |
1100 |
1011 |
1010 |
1001 |
1000 |
- 解决的办法是我们再次对负数进行重新编码,这次的改变是将所有的负数编码在之前的基础上加1,这仍然不会影响到之前已经编好的正数的编码。
- 可以看到现在+0和-0的编码都变成了0000,也就只有1个0了。再次进行上例的计算,0+(+1)+(-1)=0000+0001+1111=0000=0。0的问题也得到了解决。
- 同时,由于只剩下了一个0,那么现在16个编码对应了15个数字,即(-7,7),可以发现1000并没有对应任何十进制数。-8=(-7)+(-1)=1001+1111=1000,所以我们可以让1000对应-8。
- 至此在计算机中使用此种编码方式,既做到了让硬件只进行加法运算且硬件可以无视符号位,也解决了0的问题,可以让4位二进制数可以真真正正地表示16个数字。