世界上有10中人,一种懂二进制,一种不懂二进制。我们习惯了十进制计数,乍看到二进制,有点别扭,认识后慢慢发现它的神奇:有点一生二,二生万物的意思。十进制和二进制的部分对应关系如下:
小范围的十进制运算,我们操练起来麻麻溜溜的,二进制的运算相信你也不差,然,碰到十进制转二进制的运算就有点蒙圈了。
计算机 CPU 的运算器只实现了加法器,没有实现减法器。但,我们可以通过加上一个负数来实现减法运算。
如果你试着将3-2这个十进制运算转换成二进制运算进行计算,你就会发现,简单的翻译式计算结果不对啊,怎么能是-5(有符号数最高位1表示负,反之代表正)?
有朋友或许会嗤笑:应该把负数转换成对应的补码进行计算。相信你也对下面这几个概念耳熟能详。
-
原码:十进制数直接转二进制数得到的就是原码,简单的对应关系如下:
-
一个正数的反码、补码等于它的原码;
-
一个负数的反码:其原码的符号位不变,其它位取反;
-
一个负数的补码等于其反码+1。
负数为什么有这么多弯弯道道?从前面的3-2这个例子中,我们可以看到,简单翻译成原码计算有可能得到错误的结果。我们知道一个限定n位的二进制有符号数,表示的范围是-2n-1~2n-1-1,对于最大值2n-1-1,如果加上1,就会发生溢出(最高位是1,其它位为0,表示的是-2n-1),从最大变成了最小。这给了我们一个提醒,是否可以通过溢位来达到减法的目的?
研究发现,计算机数据的溢出,相当于取模。取模的除数就是数值表示范围的上限减去下限:2n-1-1-(-2n-1) +1=2n-1+1。这是一个步长,你会发现,无论正数或负数加上这个步长溢出后,还是它本身(n+1位置上是1,其它位置为0,n+1为溢出位)。
我们将开始的3-2变换为3-2+2n-1+1,再变换一下顺序得到:3+((2n-1-2)+1)。(2n-1-2)表示如下:
细心的你发现(2n-1-2)就是-2的反码(原码符号位不变,其他位取反),((2n-1-2)+1)就是-2补码(反码+1),显然,3-2等于3+(-2的补码)是合理的。