相关阅读
数字IC基础https://blog.csdn.net/weixin_45791458/category_12365795.html?spm=1001.2014.3001.5482
首先说明,本篇文章并不涉及补码运算正确性的证明,仅是对补码运算在有符号数和无符号数中运行进行讨论。
补码运算最大的作用在于消除计算机内部的减法器,所以实际上一个计算机中只有加法器而并不存在减法器,所有的减法操作(有符号数减法、无符号数减法)都是使用加法器完成的。
下面是补码运算的公式,其中x和y可以理解为一般意义上的十进制数,比如x为2,y为-1,则按照补码运算公式得到的是1的补码;x为1,y为-5,则按照补码运算公式得到的是-4的补码。注意这里得到十进制数的补码需要先将其转换为二进制原码,然后再转换为二进制补码。
其中需要注意的是,两个补码相加必须保证这两个补码有相同的位数,当其中两个补码位数不同时,需要将位宽短的那个补码符号拓展至位宽长的那个补码才能相加。具体操作如下,当十进制数-1的4位二进制补码1111想和十进制数2的8位二进制补码00000010相加时,必须先将1111符号拓展至11111111才能与00000010相加,得到结果00000001,即十进制数1的8位二进制补码。
两个二进制补码相加后的位宽不变,例如两个8位二进制补码相加结果仍然为8位二进制补码,这就导致了当两个正数或两个负数相加时,可能产生溢出,通俗理解就是结果不能再用8位二进制补码表示了(即需要用9位二进制补码表示)。比如对于4位二进制补码,可以表示的十进制数范围是-8到7,此时当两个十进制数4的4位二进制补码的相加时,结果本应该为十进制数8的4位二进制补码,但很遗憾4位二进制补码最高只能表示7,并不能表示8。溢出很好发现,当两个正数(二进制补码符号位为0)相加得到了负数(二进制补码符号位为1),或两个负数相加得到了正数,则可认为产生了溢出。
使用上面的4+4的例子说明,4的4位二进制数补码为0100,0100+0100得到1000即-8的二进制补码,两个正数相加得到了负数,这是不可能的,这就是溢出。如何解决这个问题呢?如果使用4的5位二进制补码相加就不会产生问题,因为5位二进制补码可以表示的十进制数范围是-16到15。具体过程为00100+00100得到01000即8的二进制补码。在计算机中,使用了OF这个标志来表示在当前的数据和当前选择的补码位宽的情况下是否会产生溢出,它的产生可以使用多种判定条件。
1、当Sa=Sb且Ss!=Sa,即两个加数符号相同,且结果与两个加数符号不同,OF置1。
2、当符号位相加的进位不等于最高有效位相加的进位时,OF置1,这也很好理解,当最高有效位有进位时,如果符号位没有进位,表示符号位都为0,此时两个符号位为0的数相加得到了符号位为1的结果;当最高有效位没有进位,如果符号位有进位,表示符号位都为1,此时两个符号位为1的数相加得到了符号位为0的结果。
上面已经讨论完了有符号数相加的情况,当有符号数相减时,使用的其实依然是最初的补码运算公式,但此时进行了一些变形。
在这个步骤中,只要把y换成y相反数的补码即可,通过一个数的补码可以很容易地得到其相反数的补码,将其所有二进制位取反加一即可(包括符号位),例如对于十进制数5的4位二进制补码0101,十进制数-5的二进制数补码即为1011。这样就将所有的减法转换为了加法,这正是补码运算的强大之处。
下面我们来谈一下无符号数的加减法,无符号数不包括符号位,但依然可以按照补码的方式加减,我们只需要给他添上一位符号位0表示其为正数即可,即对于十进制数8的4位无符号二进制数1000,在运算时可以将其看做5位二进制补码01000(其中首位0为符号位)。此时两个无符号数的加法可以看做两个有符号正数相加,若结果的符号位为则1代表有进位,就像有符号数相加产生溢出一样,进位用CF表示,但这里只会出现正数相加溢出。当两个无符号数相减时,就把减数按照有符号数相减中方式一样变成其相反数的补码然后相加,此时若结果的符号位为0(最高有效位有进位),则表示没有借位,若符号位为1(最高有效位无进位)则表示有借位(即相减结果为负),借位也用CF表示,就像是两个有符号正数相减一样。比如若相减结果为10111,可以看做结果是7并有借位,也可以看做相减结果为-9。
从上面的讨论中我们得到了一个结论:在计算机中无论是有符号数加减还是无符号数加减都是用补码加法实现的。