3.10 二进制减法
在第1章,我们简要地讨论了无符号二进制数的减法。虽然一开始只讲述了有符号数的加减法,完全排除了无符号数的运算,但是无符号数的算术运算在计算和计算机硬件设计中扮演着至关重要的作用。它可用于浮点数、有符号数的数值部分的加、减运算中,还可用来扩展定点数的精度。基于以上原因,我们将在这里讨论无符号数的加法和减法。但是,我们仍然先从硬件成本方面进行讨论,以便论证在算术运算中使用有点怪异但却广为介绍的补码表示的必要性。
在1.3节中,减法运算是先比较减数和被减数,再从较大的数中减去较小的那个数。这种包含比较操作的方法导致算法效率低下并且耗费昂贵的电路。另一个方法是,我们简单地从被减数中减去减数。使用与1.3节例子中相同的数,那么有
如果最高有效位没有借位,则减数不大于被减数,计算的结果为正数,是正确的。如果最高有效位产生借位,则减数大于被减数,结果必定为负数,这时我们需要校正该结果。当有借位发生时,我们可以通过下式的计算结果进行校正:
注意,加上的2n项表示最高有效位的借位值。正确的数值应该是N―M,用2n减去前面的算式可以得到正确结果:
前一个例子中,100000―10101=01011,得到的结果是正确的。
通常,两个n位二进制数相减,M―N,可以按以下步骤进行:
1)被减数M减去减数N。
2)如果最高位没有借位,则M≥N,结果非负,并且正确。
3)如果最高位有借位,则N>M,用2n减去差值M―N+2n,并在结果前面加负号。
用2n减去一个二进制数得到的n位结果称为该数的二进制补码(2s complement)。这样第3)步,我们可以求差值M―N+2n的二进制补码。下面举例说明在减法中使用二进制补码。
例3-19 使用二进制补码的无符号二进制数的减法
计算二进制减法01100100―10010110,我们有:
使用这种方法实现减法需要一个减法器得到初始的两数相减结果。此外,必要的时候,还需采用一个减法器对初始结果进行校正,也可用一个单独的二进制补码器对结果校正。因此我们需要一个减法器、一个加法器和一个二进制补码器执行加法和减法运算。图3-44给出了采用这些功能块实现一个4位的加减法器的模块图。输入同时加载到加法器与减法器的输入端,因此加、减运算并行执行。如果减法器的最高位借位为1,则可选的二进制补码器的补码输入端置为1。这时电路产生减法器的输出的补码。如果最高位借位为0,那么这个补码器将不改变减法器的输出结果。如果当前执行的是减法,则多路复用器的输入端S置为1,选择补码器的输出作为计算的最终结果。如果当前执行加法,则S置为0,从而选择加法器的输出作为最后结果。
正如我们所看到的,这个电路比较复杂。为了减少硬件数量,我们可以共用加法器和减法器的逻辑。这就要用到补码的概念。所以在进一步考虑复合的加减法器之前,我们将详细地探讨补码。
3.10.1 补码
每个r进制系统都有两种补码表示:基数补码(像我们前面介绍的基数2)和基数反码。前者称为r进制补码,后者称为(r-1)进制补码(又称r进制反码)。如果将基数r的值代入,这两种类型对二进制来说称为二进制补码和一进制补码(即二进制反码),对十进制来说就称为十进制补码和九进制补码(即十进制反码)。由于我们目前关心的是二进制数及其运算,故我们接下来仅探讨二进制的补码与反码。
给定一个n位的二进制数N,则其二进制反码定义为(2n―1)―N。2n表示一个二进制数,由1个1,后接n个0组成。2n–1表示一个由n个1组成的二进制数。例如,如果n=4,那么24=(10000)2,24―1=(1111)2。因此二进制数的反码可以采用1减每一位来获得。当用1减二进制数时,有1―0=1或者1―1=0,使得该位二进制数由0变为1或由1变为0。由此可见,二进制反码就是将二进制数的所有1变成0,所有0变成1,这可通过对每位求非或取反来实现。以下是两个二进制求非的实例:
1011001的反码是0100110
0001111的反码是1110000
采用同样的方法,十进制数的反码,八进制数的反码,十六进制数的反码都分别用9,7和F(十进制数15)减去每位数得到。
给定一个n位的二进制数N,其二进制补码定义为:当N不等于0时,N的补码为2n―N;当N等于0时,其补码为0。对于特殊情况N=0,由于其补码必须为n位,2n减0有(n+1)位,即为100…0,所以这个特殊值的补码可以用一个n位的减法器或丢弃最高位的1来实现。与二进制反码相比,二进制补码可以在二进制反码的基础上加1实现,因为2n―N={[(2n―1)―N]+1}。例如,二进制数101100的补码为010011+1=010100,通过在反码上加1得到。对于N=0,这个加法在忽略最高有效位的进位输出后,结果为0。对其余的基数这些概念同样适用。我们后面还将看到,这些概念在简化二进制补码和减法硬件上很有用。
同样,二进制数的补码还可以采用保留所有低位的0和第一个1不变,将剩下所有高位的1置为0、0置为1的方法来实现。这样,1101100的补码是0010100,两个低位0和第一个1不变,剩下的4个高位依次进行1变为0、0变为1的替换。对于其他的基数,其补码可用r减去第一个非零的位,剩下左边的每一位均用(r―1)去减来实现。
值得一提的是,一个数的补码的补码为其原值。因为N的补码为2n―N,而其补码的补码为2n―(2n―N)=N,得到其原值N。
3.10.2 采用补码的二进制减法
前面我们想通过共享加法和减法逻辑来简化硬件。现在有了补码,我们打算采用加法和相应的补码逻辑来定义二进制数的减法运算。两个n位无符号数的减法:M―N,采用二进制表示的计算过程如下所示:
1)被减数M加上减数N的补码,即M+(2n-N)=M-N+2n。
2)如果M≥N,则和产生一个进位位2n。丢弃进位,保留M-N的结果。
3)如果M<N,则和不产生进位,第一步的运算相当于执行了2n-(N-M),即N-M的补码。对结果进行纠正,对和求补,并在前面添加一个负号得到最终结果-(N―M)。
下面的例子进一步说明了前面的过程。需要注意的是,虽然我们处理的是无符号数,但是在步骤3)没有办法得到一个无符号的结果。当用纸和笔演算时,由于最后没有进位,结果转换为一个负数。如果要存储结果的负号,那它必须和正确的n位结果分开来保存。
例3-20 使用二进制补码加法的无符号数减法
给定两个二进制数X=1010100和Y=1000011,采用二进制补码实现X―Y和Y―X。这样有:
■
虽然无符号数减法可以使用二进制反码来完成,但在现代设计中很少用到此方法,所以在此将不作介绍。