计算机在存储整数数据,常用的存储方法就是补码,等于补码,我们总是被告知正数的补码等于原码,负数的补码等于反码,再去加1。下面我就讲讲我对这个反码的理解。
在下面的讲解,我们都假设计算机用一个字节(也就是8位)的大小来存储整数,也就是最多存储(2^8=256)个整数。
对于负数,从数学上,我们是这么定义的:a的相反数就是a加上这个数后等于0。我们先不讲补码,先看看数据溢出。
由于计算机的存储数据有限,所以在计算时会出现数据溢出,例如(177_{10}(1011 0001_2)+100_{10}(0110 0100)=277_{10}(1 0001 0101_2)),但由于数据溢出,结果为(21_{10}(0001 0101_2))。通过溢出,我们可以发现,如果数a加上数b后的结果刚好后八位都为0(即(000 0000))的话,那么a+b的结果就是0,这不就刚好和我们在数学上定义的负数一样吗?换句话说,b就是a的相反数。
所以,求a的负数,等于用"(0000 0000)"减去a的二进制数。我们知道两个位数相同的数相加,结果的位数最多比加数多一位。如果数据溢出的话,溢出的这一位(结果比加数多出的那一位)肯定不是0,我们便推导出(a+(-a)=1 0000 0000_2(255_{10}))。所以我们只需用(1 0000 0000_2)减去a的二进制数便可得到a的相反数。又由于(1 0000 0000_2=1111 1111_2 + 0000 0001),所以( ext{a的相反数=}1 0000 0000_2 - ext{a的二进制数}=1111 1111_2 - ext{a的二进制数} + 0000 0001),为了方便看出数据,我们假设(a=11_{10}=0000 1011_2),而(1 0000 0000_2 - 0000 1011_2 = 1111 0100_2),结果恰好为11的二进制数的取反,再将结果(+0000 0001)就是11的相反数。这就解释了为什么负数的补码等于正数的反码加一。
通过上面的分析,我们可以看出正数的相反数就是用(2^8-1=255_{10}, ext{即}1 0000 000_2)减去这个正数。所以我们可以把(2^8)个数分成两部分,第一部分为0到(2^7-1)作为正数,第二部分为(2^7)到(2^8-1)作为负数,这种分法就是8位中第一位为0的作为第一部分,为1的作为第二部分。