补码表示是数值计算中的一个基本技术,它使得减法操作可以用加法操作来替换。
这篇文章首先用几个例子来回顾补码表示的理论。然后,我们将简单地讨论加法器/减法器的框图。
补码表示是数字计算机表示有符号整数的一种方式。补码表示的主要目的是用加法操作来代替减法操作。通过这种方式,我们可以用同样的电路来处理加法和减法。因此,可以减少门电路的数目,从而减少整个电路系统的大小,能耗。事实上,如果不使用补码表示,我们只能用一种类似平时手算十进制数的方式,这需要两种不同的门电路块来计算加法和减法。此外,在计算之前,还需要一些执行逻辑判断。
知识背景:无符号数的计算
假设我们有一个加法器,输入是两个4比特无符号数,a=a3a2a1a0 和 b=b3b2b1b0,还有一个进位输入信号cin,然后计算它们的和 a+b+cin。要怎么用这个加法器来实现减法操作呢?比如,S = a - b? 在S上减去一个常数M,再减去M, S的结果不变:
当M足够大时,可得:
所以等式1可以写成:
等式3需要一个加法操作和一个减法操作。另外,为了计算B,还需要一个减法操作。看上去把运算变得更加复杂了,因为只需要一个减法操作,而等式3需要一个加法操作,两个减法操作。但是,等式3计算需要的两个减法都是减去同样的常数M, 我们是否能找到一个合适的M,来简化等式2和等式3中的减法操作。如果可以,就能用等式3达到用加法实现减法的目的。所以问题变成:常数M的合适值是多少?在后文会被证明,对于k比特的数,
假设一个4比特无符号数b, 测试减法 .
,所以 。
为了简化运算,可以把M写成 ,代入等式2:
可以很简单地计算,因为事实上是对b按位取反。假设,则
可以看出,括号里的减法其实是b按位求补。因此,要算,只需要对b按位求补再加上. 在后文会提到,从实现的角度,对一个数的按位求补加上是很简单的
得到B之后,可以用加法器计算等式3中的a+B。为了得到最后的结果,还需要把a+B的结果减去M。在上面的例子中,我们考虑的是4比特的无符号数,因此,S能取得最大值时,应该是和,得到. 所以4比特是足够表示4比特减法的。选择 ,加上M或者减去M,只能影响第5位比特的值。所以,,第5位比特值改变第一次。接着,,第5位比特值改变第二次。因为是二进制,则第5位比特值没有改变,所以当计算时,只需要丢弃的第5位比特值即可。事实上,这等价于对作模M运算,限制的值小于等于M-1
上述讨论总结为:如果a和b是两个k比特的无符号数,则a-b等价于计算a加上M-b,然后丢弃第k+1位比特值。在这里M等于
在模M运算中,M-b被称为b的补码(two's complement). 一个数的补码可以通过对这个数按位求补再加1得到。
例子1
a,b均为无符号4比特数,用补码表示计算a-b,,
因为是4比特数,所以。根据上述理论,先求
再把a加上B,
再丢弃第5位比特值,得到
例子2
a,b均为无符号5比特数,用补码表示计算a-b,,
因为是5比特数,所以。根据上述理论,用M-b表示-b,先求
再把a加上B,
再丢弃第6位比特值,得到
怎么表示有符号整数呢?
将b和M-b相加得到M,而M在模为M的运算中等于0;这也是为什么在模为M的运算中,M-b可以看做是b的补码。在表格1的第二列给出了所有3个比特位的可能组合。相对应的十进制数值放在第一列。假设,对应的补码放在第三列。可以发现,在模为M的运算中,第二列加第三列的值等于0. 表格展示出,一个3比特位的数值可以有两种不同的解释。比如,010可以是解析成正十进制数2,或者负十进制数-6.为了区分这两种情况,我们在最左边增加一个额外的符号位,用来区分数值是正数还是负数。
当符号位为0,表示该数为正数。在此示例中,剩下的3个比特位根据上表的第一列给出对应的十进制的大小。比如,,表示+2. 当符号位1,表示该数为负数,必须要使用上表的第三列来解析。比如,应解析成-6. 事实上,我们使用4比特位来表示一个有符号的大小为3比特位的数。
现在让我们加上符号位,并实验所有可能的组合。图一展示了4比特位数值的所有可能的组合。如果设定这些数为无符号数,则我们得到圆圈外面的数值。如,无符号数等于十进制数10. 如果设定这些数为有符号数,则我们得到圆圈里面的数值。如,无符号数等于十进制数-3.
从图1可以看出,补码常数M 为 。比如,一个负数-5,表示为. 所有的负数的符号位都为1,当我们处理有符号数时,这个有助于我们在系统里判断负数。
图1也展示了有符号数和无符号数的数值表示范围。用无符号数表示,4比特位可以表示 ~ 的数值范围。用有符号数表示,4比特位可以表示 ~ 的数值范围. 需要注意有符号补码表示的范围的非对称性。该特性可能会导致数值溢出,程序员需要谨慎地处理去避免这种情况发生。
小节总结:当我们假设一个有符号的补码表示,首先要关注符号位。 如果符号位为0,可以像无符号数一样处理得到十进制数值。如果符号位为1, 相关的十进制数值是该补码表示的补码。如,按位求补得,再加1,得即3. 所以表示-3。
例子3
假设有一个有符号的补码表示,找到和对应的十进制数值。
因为a的符号位为0,是正数,所以
因为b的符号位为1,是负数,所以
现在,我们熟悉了有符号的补码表示,可以更简单地实现加法和减法。
例子4
假设有一个有符号5比特位的补码表示,有和,计算a-b。
为了计算a-b,需要找到-b,去加上a.
遂,
,
由于是5比特位的运算,所以丢弃第6位,得到
例子5
假设有一个有符号5比特位的补码表示,有和,计算a-b。
为了计算a-b,需要找到-b,去加上a.
遂,
,
由于是5比特位的运算,所以丢弃第6位,得到
将结果转换为十进制,
在上述两个例子中,我们丢弃了第6比特位的数值,但结果是正确的,因为补码表示是基于模M运算的。
例子6
假设有一个有符号5比特位的补码表示,有和,计算a-b。
为了计算a-b,需要找到-b,去加上a.
遂,
,
由于是5比特位的运算,所以丢弃第6位,得到
然而,实际上. 这是因为5比特位最大能表示的正数是. 这个例子说明我们总是需要检查计算的结果去保证没有数值上溢发生,从而保证计算结果是正确的。数值上溢发生在,两个正数相加导致结果为负数,还有两个负数相加导致结果为正数。由于补码的性质,一个正数和一个负数相加不会引起数值上溢。
简单加/减法器的框图
就像本文开头所说,补码表示就是为了在同一个电路模块上执行加法和减法。如下图所示,输入为二进制数a和b,还有输入进位, 输出为a+b+.
当标志位sub/add为0, Selective complement不执行 , y=b,, 因此结果为a+b+。
当标志位sub/add为1, Selective complement执行,对b按位取补 , ,,结果为。按上文所说等于y的补码。所以加法器的最后输出的其实是x-y