接下来我们将在加法器基础上扩展实现减法功能。
首先从我们最熟悉的十进制加法开始
只考虑被减数大于减数的情况
比如说253减去176
首先从最右列着手
6是大于3的,因此从5上借1,再用13减去6,得到结果为7
由于我们已经在5上借了1,因此,现在实际上那一位是4
而4是小于7的,因此继续从2上借1,
14减7结果为7。而由于在2上借了1
实际上这一位是1,从中减去1,结果为0。
因此,最后的结果应为77:
现在我们用一个小技巧来让减法不涉及借位
为了避免借位,首先要从999中减去减数,而不是从原来的被减数中减去减数
由于操作数是三位数,所以这里使用999。
如果操作数是4位,则用9999。
从一串9中减去一个数叫做对9求补数。
176对9的补数是823。
反之亦然:823对9的补数是176。
这样的好处就是无论减数是多少,计算对9的补数都不需要借位。
计算出减数对9的补数后,将补数与原来的被减数相加:
最后再将结果加1,并减去1000。
到此,我们就得到了结果。
答案与先前的相同,而且没有用到借位。
为什么这种方法行得通呢?
原题目是这样的:
253-176
在这个式子中加上一个数再减去这个数,
结果是相同的。
因此先加上1000,
再减去1000:253-176+1000-1000
这个式子与下式等价:
253-176+999+1-1000
然后用以下方式将数字重新组合:
253+(999-176)+1-1000同样的技巧可以用于二进制数中
而且实际上这要比十进制数简单
让我们一起来看看该如何操作
将这些数字转化为二进制数,问题变为:
第一步,用11111111(即255)减去减数
当计算十进制数减法的时候,
减数是从一串9中减去的,结果称为9的补数。
在二进制数减法中,减数是从一串1中减去的,结果称为1的补数。
但是请注意,我们在求对1的补数时并不需要用到减法。
在求对1的补数时,只需将原来的二进制数中的1变为0,将0变为1即可。
第二步,将减数对1的补数与被减数相加:
第三步,将上式所得结果加1:
第四步,减去100000000(即256):
结果就等于十进制数的77
加法器中新增部分为一个用来求8位二进制数对1补数的电路。
之前提到,二进制数对1求补数相当于对其每位取反,
因此我们计算8位二进制数补数的时候可以简单地应用8个反向器。
问题是,该电路只会对输入求反,
而我们要的是一台既能做加法又能做减法的机器,
因此就要求该电路当且仅当进行减法运算时才实现反转。
电路可以改造为如下图所示。
标记为"取反"的信号将被输入到每一个异或门中。
回想一下异或门的工作方式,如下表所示。
如果"取反"信号是0,则8个异或门输出与输入相同。
例如,如果输入是01100001,那么输出也为01100001。
如果"取反"信号为1,则输出信号反置。
因此在原有加法器的基础上,增加一个取反器,我们就可以进行减法的计算了
第一个电路与此前的八位加法器非常相似。
但是请注意,左侧的加号现在变成了一个按钮。
点击该按钮即可切换加减法。
一组XOR门会反转第二行按钮的值(计算反码,也就是求对1的补数)
这个按钮还有其他作用
它将右侧的Carry In设置为1,也就是+1
同时在最后与第8个加法器的输出进行异或,相当于是减了100000000
当您选择用第一个数减去第二个数时,
如果加法结果大于255,或减法结果小于零,
Overflow将会发光,表示结果无效。
此前没有提到负数在二进制中是如何表示的
你可能设想二进制会同十进制一样应用传统的负数符号
例如,-77在二进制中为-1001101
这样做当然可以
但是应用二进制数的目的恰恰就在于只希望用0和1来表示所有的东西
当然也包括负号
当然,你可以简单地用一个二进制位来表示负号
当这一位为1的时候就表示负数,为0则表示正数,
尽管这样也是可行的,但还不够好
首先,借鉴一下现有的这个表示正数、负数的方法
…-1000000, -999999…-3, -2, -1, 0, 1, 2, 3…999999,1000000…
可以表示无限的正数和负数
但是如果我们并不需要无限大或无限小的数
而且在开始的时候我们就可以确定所使用的数字的范围
那么情况会不会不一样呢
举个例子
有一张银行卡,银行给了500元无息预支额度
但这张卡的余额不会达到500元
而且每次存取都是整数,不涉及角、分
意思是卡的余额是在-500元到499元的数
-500到499一共1000个数
而0到999也是1000个数,这表明我们只需三位数就能表示余额值
并且不需要负号
0到999中,把0到499给正数余额使用,500到999用来表示负数
具体情况如下:
用500表示-500
501表示-499
502表示-498
******
用998表示-2
用999表示-1
用000表示0
用001表示1
*****
用498表示498
用499表示499
我们把-500到499
从-500, -499, -498 …-4, -3, -2, -1, 0, 1, 2, 3, 4 … 497, 498, 499
表示成这样
500, 501, 502 … 996, 997, 998, 999, 000, 001, 002, 003, 004… 497, 498, 499
如果你能看到这里
那么恭喜你,你已经掌握了怎么将三位负数转化为0的补数了
例如想要得到-255对10的补数,用999减去255得到744,然后再加1,得到745
你可能听说过:"减一个数就等于加一个负数。"
然而,利用10的补数,我们将不会再用到减法。
所有的步骤都用加法来进行。
继续回到刚才的银行卡
假设卡里余额143元,你现在需要再使用78元
也就意味着要将一个值为负的78元加到143元上
-78对10的补数为999-078+1,即922
因此新余额为143+922,等于1065,忽略溢出就是65元
现在再消费150元,-150对10求补数是850
因此850加上剩下的65等于915
915是谁的补数?是-85的,因此现在卡里余额实际上是-85
在十进制中理解,在二进制中践行
现在需要表示的数的范围是-128~+127。
最高有效位(最左位)作为符号位(sign bit)。
符号位中,1表示负数,0表示正数。
计算2的补数,等价于将每位取反再加1
-125的对2的补数,首先将01111101的每位取反,得到10000010,再加1,得到10000011
这个系统为我们提供了一种不用负号就能表示正、负数的方法。
同样也让我们自由地将正数和负数用加法法则相加。
例如,将与-127和124等价的两个二进制数相加。
利用上面的表格,可以简单地写为:
结果等于十进制的-3
可以用下方的补码加法器进行验证
以下加法器专门用于相加两个八位补码数,
范围从80h(十进制-128)到7Fh(十进制127)。
您选择的值的十六进制和十进制等效值显示在右侧。
如果一个值为正而另一个为负,
结果总是有效的,
因为此时Overflow值为0。
但如果两个值都为正且和大于127,
或两个值都为负且和小于-128,
Overflow值为1,且会发光,表示数据有溢出。