为什么被减数减去减数等于被减数加上减数的反码?补数怎么来的?为什么用补数?可溢出计数系统

> 十 进 制 减 法

通常我们用十进制进行减法的时候通常会出现以下两种情况:

  • 不需要借位:如“456-123”
  • 需要借位: 如“253-176”

对于不需要借位:我们可以直接相减即可

对于需要借位的:我们可以通过一系列操作来免去借位
如:

253 - 176 = 253 + (999 - 176) + 1 - 1000
                 =1077 - 1000
                 =77
// 此处我们 通过引入 9 的补数 来避免借位

上面我们引出了补数的概念,一个数的补数即为:在这个数所处的进制系统里,这个数的每位最高位 - 这个数 + 1

在这里我们运用了:“被减数 - 减数 = 被减数 + 减数的补数 - 减数每个位最高位
————————————————————————————————————
那么对于结果是负数的该怎么办呢,比如:“176-253”
我们仍用上述的方法来试一下::

176-253 = 176 + (999 - 253) + 1 - 1000
======= = 922 - 999
// 我们可以看到这里还是得借位,不过我们只要把减数和被减数调换位置,然后在前面加上负号就可以了:- ( 999 - 922)

在被减数小于减数的时候,我们仍然运用了:“被减数 - 减数 = 被减数 + 减数的补数 - 减数每个位最高位,只不过最后将减数和被减数调换了一下位置,然后再加个符号


二进制减法

上述例子:”253 - 176“ 的二进制减法:

        11111101
      -10110000
      -------------------
      =11111101 + (11111111 - 10110000) + 1 - (100000000)
      =101001101 - 100000000
      =1001101
      =77(十进制)

不知道聪明的小伙伴发现了没有,在二进制系统中求一个数的补数,其实没有必要使用减法,由于二进制系统只有”0“,”1“构成,求一个数的补数只需要把那个数的0变成1,1变成0即可,所以上述过程可以简化为:

        11111101
      -10110000
      -------------------
      =11111101 + (01001111)+ 1 - (100000000)
      =101001101 - 100000000
      =1001101
      =77(十进制)

对于 ”176 - 253“:

        10110000
       -11111101
      -------------------
      =10110000+ (00000010)+ 1 - (100000000)
      =10110010 - 11111111
      = -(11111111 - 10110010)
      =- 77(十进制)

减法该如何实现呢?

前面我们一直在讨论怎么把减法变成加法,但那只是我们在脑海中的运算,至于在计算机中,我们还没有说明,在说明之前,我们先来讨论一下”负数该如何表示“?

负数的表示方法

  • 像十进制中用”+“,”-“表示?,显然是不太可行的,因为二进制中只有0和1
  • 用0表示正,1表示负?好像可行,但是还远远不够

通常用来表示负数和正数的方法,他的好处在于能给表示除所有的正数和负数。我们将0想象为这个无限妍伸序列的中点:
…-99999999,  -99999998…  -3,  -2,  -1,     0,   1,  2,  3…9999999,10000000,…999999999…

以支票账户为例,这里人们通常会遇到负数。假设我的账户有499元,可透支500元,那么我们能处理的额度为:-500 - 499,这个约束说明只用三位十进制,而不用负号就能表示我们所有的数字,但我们并不需要500——999之间的整数,因为我们所需要的最大值为499,那么我们可以用500-999之间的数表示负数:

-500,-499,-498.。。。-4,-3,-2,-1  0   1,2,3,4…498,499 可以表示为
 500 ,    502 , 503          996 997 998 999 0 , 1 ,2 ,3 ,4 …499

注意:这就形成了一个循环排序。最小的负数(500),看起来像是最大整数(499)的延续。而数字999(实际是-1)是比0小1的第一个负数,如果我们在999(-1)上加上1,则会得到1000,由于我们处理的是三位数,这里则是0.

我们可以把这些数字想象成钟表上的刻度,时钟的十二点初代表0,顺时针有 1000个点,最后一个点是999:为什么被减数减去减数等于被减数加上减数的反码?补数怎么来的?为什么用补数?可溢出计数系统

而原先则是12点处为0,顺时针为正,逆时针为负:
为什么被减数减去减数等于被减数加上减数的反码?补数怎么来的?为什么用补数?可溢出计数系统
这种标记法称为10的补数,为了将三位负数转换成10的补数,我们用999减去它再加一:
如:-255 = (999-255) + 1 = 745;

假设你游一个余额为148元的账户,开了一张78元的支票,那就意味着你的可操纵钱变为了:148 - 78,也就是(-78) + 148;-78对于10的补数为(999-78+1)= 922,那么新余额为:(148+922 )-1000= 65(忽略溢出)。如果我们又开了一张150美元的支票,需要在余额上减去150,(-150)等于(999-150+1) = 850,新余额为(65+850)-1000=-85

上面的减去1000是因为这个三位十进制系统最大容量为1000,超过1000就要溢出,这也解释了上面二进制和十进制减法为什么最后要减去一个数,那个数就是系统的最大容量(或许当时你看的时候就发现疑问了,因为当时我们只是用一种特殊的方法来避免做减法,而没有把他放进一个系统中看待,现在我们有了模型,就会更容易的理解为什么减法可以换成加法了)。


这种机制在二进制系统中称为二的补数,以八位二进制系统为例:00000000——11111111代表0 —— 255,此处无符号位:

为什么被减数减去减数等于被减数加上减数的反码?补数怎么来的?为什么用补数?可溢出计数系统

但是,如果我们还想表示负数的话,我们可以把左边第一位做为符号位,其他七位用来计数,则就可以表示:”0——127“ 和 ”-1—— -128“。为了计算2的补数,我们只需要计算出1的补数再加1即可。

比如我们要计算-127 和 124 相加,即”1111 1111“ + ”0111 1100“ ,对”1 1111111“求补:”1 0000001“
变为”10000001“ + ”0111 1100“ = (1 1111101) = - 3

要注意的是,这里涉及到了上溢和下溢的情况(结果>127或<-128),比如125 + 125 = -6,这是由于我们规定所处理的数值为8位,因此最左位常常被忽略。右边八位相当于十进制的6.

一般来说,如果两个操作数符号相同,结果的符号数与操作数符号不同,则这样的加法是无效的

因此我们在做加减法时,必须要提前算一下数字所使用的范围,这也是可溢出计数系统的缺点。

最后,我要膜拜一波那个把数字放到一个可溢出计数系统中(可以想象成钟表)来进行操作的人,完美的避开了负数带来的麻烦,把所有的运算都转化为了加法!!!

!!!!!!!勇哥牛逼!!!!!!!