上一篇编码:隐匿在计算机软硬件背后的语言(4)--二进制减法器中,我们在减法器中对于减数大于被减数的情况当作溢出处理,实际上是由于加法器无法表示负数(至少在本文之前),本文的主题就是讨论负数的表示。
同样先对十进制进行分析(易于理解),然后过渡到二进制。
我们知道数字是没有界限的,然而我们所用到的数字都是有限的。所以先以三位十进制数为例。三位十进制数的范围为000-999,我们用这一千个数来表示-500~499。我们打算不用负号来表示负数,因为计算机里所有的信息都是用二进制来表示的,包括负号“-”。下面是我们的方法,以0为中心:
也就是说以5、6、7、8、9开头的数字都是负数,这样
-500,-499,-498,...,-1,0,1,...,498,499
就可以表示为
500,501,502,503,...,999,0,1,2,...,498,499
可以注意到这形成了一个循环序列,最小的负数500看上去像最大整数499的延续。
我们也可以这么理解,十进制有符号三位数可以表示为500,501,502,503,...,999,0,1,2,...,498,499。当然无符号三位数还是原来的000~999。
上面的这种标记法称为10的补数,如果看了上一篇就会知道,我们在实现减法器的时候用到了对9的补数,实际上对10的补数结果等于对9的补数加1。例如-255对10的补数为(999-255+1)=745。
有了10的补数,我们将不会再有减法。例如143-78=?计算机就会这么处理(假设计算机是十进制的),-78的补数是(999-078+1)=922,143-78=143+922=1065,由于是三位数,(最高位忽略)得到65。而65-150=65+850(150对10的补数)=915,实际上这就是-85。
下面我们看看二进制。同样的在二进制中,我们需要求减数对2的补数。以有符号的8位二进制为例,0000 0000~1111 1111(十进制中0~255)以0为中心可以得到以1开头的数字都是负数,如下图所示
也就是最高位成了符号位(有符号十进制中,最高位也是符号位,不过符号位数字为5、6、7、8、9)。
二进制中为了计算2的补数,先计算1的补数然后加1。二进制中可以简化为取反然后加1。
这样我们不用负号就可以表示负数。
例如-127+124=1000 0001 + 0111 1100(124对2的补数)=1111 1101,实际上这就是-3。
需要注意的地方就是,这里涉及到上溢和下溢的问题,例如125+125=1000 0011+1000 0011=1111 1010,以1开头,是负数-6,两个整数相加成了一个负数;同样的情况对负数也一样,-125+(-125)=1000 0011+1000 0011=1 0000 0110 由于是8位,这个数字是+6,两个负数相加成了一个整数。
这样的加法是无效的。此时我们需要更多的位数来表示这些数字。
从上面可以看出,三位无符号十进制数的范围为000~999,三位有符号十进制数(姑且这么说)的范围为-500~499。同样,
8位无符号二进制数范围为0000 0000~1111 1111(0~255),8为有符号二进制数的范围为1000 0000~0111 1111(-128~+127)。
所以我们必须弄清楚是有符号数还是无符号数,这也是二进制的麻烦之处。