微处理器用二进制补码系统表示有符号整数,因为它可以将减法运算转换为对减数的补数的加法运算。

1.什么是二进制补码运算

    我们先引入补数的概念:

补数:一个数与它的补数之和是一个常数。例如一个一位的十进制数与它的补数之和总是9,2的补数是7,4的补数是5。在n位的二进制算术中,数P的补数Q=2^{n}-Q(即常数是2^{n})。 

    令n位二进制数N的二进制补码定义为2^{n}-N。如果N=5=00000101(8位二进制数),则N的补码为2^{8}-00000101=100000000-00000101=11111011(注意此处11111011用于表示5的补码,不要看成无符号整数)。

    下面看几个例子:

5:00000101,5的补码:11111001   

7:00000111,7的补码:11111001

    例1:将7与5的补数相加

00000111 + 11111011 = 1000000010

    结果为9位二进制数100000010。由于一共只有8位,我们忽略最左边一位,结果为00000010,也就是2。即7与5的补数相加结果为2,效果等同于7-5=2。

    例2:将7的补数与5相加

11111001+00000101=111111110

    结果为9位二进制数111111110,忽略最左边第九位后结果为11111110,“刚好”是二进制2的补码(2^{8}-00000010=11111110),也就是5-7=-2。

    从上述例子看,在二进制运算中,对于正数N而言,减去N的操作和加上N的补数的操作效果是相同的,也就是说-N等价于N的补数

    那么,为什么要引入补码运算呢? 

2.用补数的加法代替减法   

    二进制补码算术不是魔术,具体展开看,在n位的二进制算术运算中,我们令Z=X-Y,我们试着用X加上Y的补数来运算,由于Y的补数为2^{n}-Y,所以

X+Y的补数=X+(2^{n}-Y)=2^{n}+(X-Y)=2^{n}+Z

    换句话说,我们用X加上Y的补数会得到Z加上2^{n},但2^{n}只体现在最左边的第n+1位(如同上述例子中第九位的1),会被丢弃掉。所以此时我们得到了Z=X-Y=X+Y的补数,也就是说,在二进制补码运算中,减去一个数,等同于加上这个数的补码

    到这里,我们可以进一步直接放心地在二进制补码运算中用一个数的补码来表示这个数的负数了,如果不放心,我们还可以证明,对一个数进行两次求补将得到这个数本身:例如

-5=2^{8}-00000101=11111011

再次求补:-(-5)=2^{8}-11111011=00000101=5

    我们考虑加法的所有情况,请看下面的实例。令

X=9=0000101, -X=11110111

Y=6=00000110, -Y=11111010

    此时有

X+Y=00000101+00000110=00000111=15

X-Y=00001001+11111010=100000011=3(红色最高位舍弃)

-X+Y=11110111+00000110=111111101=-3(3的补码)

 -X-Y=11110111+11111001=111110001=-15(15的补码)

    结合之前所有的论证, 上述所有4中加减法中的情况都正确得到了我们想要的结果,例如将6与9的补码相加完成运算-9+6,得到-3,确实是3的补码。

3.求补运算

    我们现在可用补码加法来代替减法了,但是,例如N的补码是2^{n}-X,我们求补的操作本身不就是一次减法吗?!别急,补码运算可没这么蠢,求补的运算是非常简单的。我们将表达式2^{n}-X表示为下面的形式:

2^{2}-X={\color{Blue} 2^{n}-1}-X+1={\color{Blue} {1000...0}-1}-X+1={\color{Blue} 111...1}-X+1

    例如,8位(n=8)时有

2^{8}-X=100000000-X={\color{Blue} 100000000-1}-X+1 ={\color{Blue} 11111111}-X+1

    表达式111...1-X的值很容易计算。对于X的第i位n_{i},如果n_{i}=0,则1-0=1,同样,若n_{i}

=1,则1-1=0,很显然,取n_{i} 的反就行了,换句话说计算111...1-X部分的值只需要将X每一位取反。可见计算X的补码非常容易:

计算数N的补码,所要做的就是将X的每一位取反,然后将取反结果加1。

    例如,对于二进制的6=00000110,6的补码为11111001+1=11111010。

    这种补码运算相对于减法来说,非常适合用硬件实现,效率也很高。

4.补码的特点

  1. 补码是一个真正的互补系统+X+(-X)=0;
  2. 补码0被表示为00...0,是唯一的;
  3. 补码的最高位为符号位,如果符号位为0,则该数为正;符号位为1,则该数为负;
  4. n位二进制补码数的表示范围为(-2^{n-1})~​(2^{n-1}​​​​​​-1),例如对于n=8,补码的范围为-128~127.共有2^{8}=256个不同的数(128个负数,1个0,127个正数);
  5. 补码加法和减法可以使用同样的硬件完成,因为补码减法由被减数加上减数的补数实现。

 5.运算溢出

     n位二进制补码数的表示范围为 (-2^{n-1})~​(2^{n-1}​​​​​​-1)。如果运算结果位于这个范围之外会发生什么呢?

    我们令5位有符号二进制补码数的表示范围为-16~+15,考虑下面的例子:

    情形1:5+7=00101+00111=01100=12

    情形2:12+13=01100+01101=11001=-7

    在情形1中,我们得到了期望的结果+12,但在情形2中,我们得到的结果是一个负数,因为它的符号位是1,如果将他视作无符号整数,它将是2^{4}+2^{3}+2^{0}=25,但是我们不可能将两种解释应用到一个表示方法中,所以一旦采用了补码表示,那么11001就只能表示-7。

    同样,如果两个负数相加且结果小于-16,也会超出5位二进制补码的表示范围。

    情形3:-9-12=10111+10111=101011

    在情形3中,第六位1舍弃后,结果为正数01011=11。

    这两个例子都说明了什么是运算溢出,它发生在补码加法当两个正数的和为负数,或两个负数的和为正数的时候。也就是说,如果操作数A和操作数B的符号位相同,但结果的符号位与它们不同的时候,则可以判定发生了溢出。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐