计算机自底向上(二):二进制减法
作者:互联网
在上一篇随笔中我们实现了一个位数任意多的二进制加法器,在这里我们进一步去考虑下一种运算:减法运算。事实上我们不需要一个减法逻辑;我们需要的是一个负号,因为A - B = A + (-B)。用负号的好处还在于我们也顺手实现了负数的逻辑,不会让0 - 1变成一个无意义的结果。为此我们需要一个bit来储存我们的符号。
让我们想想,在自然情况下,0应该代表正号而1代表负号,因为你不希望10代表-0而是代表一个无符号的2。让我们先把这个符号位当作一个单纯的正负号,直觉上我们应该有如下结果:
5 = 0 101,-5 = 1 101
这是十分自然的,因为现在1就相当于一个负号。让我们把5和-5加起来,我们希望得到一个0;但很不幸的是我们失败了:
0101 + 1101 = (1)0010 = 2 != 0
记住,我们的位数是有限的,因此溢出的1会被我们抛弃。
直接把1添加到数字的前面构成其相反数的方法行不通,我们进入了未知领域。让我们考虑一下我们还可以做什么;抱着尝试一下的心态,我们把负号保留,而把5的每一位都做一次非运算(取反,A的取反记为~A),来构成我们的-5:
5 = 0 101, -5 = 1 010
然后再相加:
0101+1010 = 1111
很快我们就会发现,因为我们的位数是有限的,我们马上就可以得到我们想要的0:
1111 + 0001 = (1)0000
让我们再小心地尝试别的数:
5 = 0 101, -2 = 1 101
0101 + 1101 = 0010, 0010 + 0001 = 0011 = 3 = 5 + (-2)
我们取得了胜利。这是一个简单而自然的计算方式,并且能给出正确结果,实现起来也非常简单:我们在收到一个要做减法的信号时,保持被减数不变,把减数按位取反(非门),相加后再把输出送回输入并且加上一个1,就能得到正确的结果。不过我们还有一个更加聪明的办法;我们的全加器是有一个进位输入的。大多数进位输入被上一个全加器的进位输出连接,但是第一个全加器的进位输入是空的。这意味着我们可以在这个进位输入中加入一个1,根据加法结合律,A+(-B)+1 = A+(-B+1),所以我们会先把B取反,再加上一个1,而不是先加上A。这样做还有一个好处,那就是A的取反加1的结果(~A+1)与A相加是0,从而~A+1是真正意义上的A的相反数。
我们将~A称为A的反码,而~A+1称为A的补码。当我们要计算减法时,只需要把把减数变成它的补码,再和被减数相加,就可以得到正确的结果。我们得到这个结论的方式也许是猜测和运气,但却不无根据;事实上,这是一种被称为模算术或者时钟算术的数学。这里是一篇关于补码和模算术的文章,介绍了更多细节。
好了,我们有了许多理论准备,并且给出了一个实现方式。基本上,我们要依靠一大堆的非门来实现取反,并且要求这个非门被减法信号控制:当减法信号为1时,数据就要取反,不然就不取反。有没有办法简化这一过程?这个逻辑过程可以列一个真值表:当减法信号为1,数据输入0就输出1,输入1就输出0;否则不变。这还是异或门的逻辑;所以我们可以将数据输入和一根信号线连接起来加上一个异或门,并且信号线连接最低位的加法器的进位输入:此时输入0为加法,输入1为减法,自动完成了补码的转换。
标签:底向上,二进制,取反,一个,减法,101,我们,输入 来源: https://www.cnblogs.com/nanonano01482/p/16610486.html