首页 > 技术文章 > 补码

h-hg 2018-03-02 23:09 原文

  计算机在存储整数数据,常用的存储方法就是补码,等于补码,我们总是被告知正数的补码等于原码,负数的补码等于反码,再去加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\),所以\(\text{a的相反数=}1\ 0000\ 0000_2 - \text{a的二进制数}=1111\ 1111_2 -\text{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},\text{即}1\ 0000\ 000_2\)减去这个正数。所以我们可以把\(2^8\)个数分成两部分,第一部分为0到\(2^7-1\)作为正数,第二部分为\(2^7\)\(2^8-1\)作为负数,这种分法就是8位中第一位为0的作为第一部分,为1的作为第二部分。

推荐阅读