四、整数符号问题:补码
补码是困扰许多学生的一个难题,但这个问题如果不能深刻理解,在学习C和C++中的过程当中会有很大的困扰,因此必须攻破这个难关。
1、要提出和巩固的是“模”的概念。实际上在前面讨论整数范围的时候,已经涉及到这个问题。
模的概念:“模”是指一个计量系统的计数范围。
例:时钟的模为12,计量范围是0~11。若时钟指向11,则再过1小时,时钟将指向0(即12)。
例:n位计算机数的模为2n,计量范围是0~2n-1
对于有模的计数系统来说,任意整数R恒等于R+k*mod(k为任意整数,mod为其模值),或者说两个整数之间如果相差模的整数倍,那么它们就是等价的。
例:时钟的模为12,则+8点和-4点是等价的。(比如可将+8理解为顺时针拨8格,而-4理解为逆时针拨4格即可)
例:8位计算机数的模是256,则255和-1是等价的,254和-2是等价的,……,128和-128是等价的!
当然这里必须强调,这种等价的前提一定是因为这里的计数系统和时钟一样是一个封闭的环。如果是普通的数轴,是根本不可能如此的。
2、引入补码的思想。为了表示负数,将原有计数范围劈成两半,其中数值较小的一半保持不变,而数值较大的一半则用来表示对应等价的负数。
例:原有的时钟表盘是0~11,使用补码之后则表示为-6~5。其中0~5是保持不变的一半,而-6~-1则是由6~11的一半等价转化而来的。
例:8位计算机数原有的范围是0~255,使用补码之后则表示为-128~127。
注意:在上述转换过程中,0被看作为正数,而中间值(6和128)则被转换为对应的负数,这样可以保证正数和负数的个数是一样的。
有了补码之后,计算问题就迎刃而解了。任何有模的计量器,均可化减法为加法运算,化负数为正数表示。
例:在8位计算机数的范围下,用补码原理计算 6 - 2。 6 - 2 = 6 + (-2) //化负数为整数,化减法为加法。 = 6 + 254 // -2和254在本题的背景下是等价的,也就是说ALU在运算的时候仍然看成是254。 = 260 = 4 //260和4在本题的背景下是等价的,而且只能表示为4,因为260超出了范围。
上面这个例子中,我们人看到的是负数-2,但计算机在运算的时候实际是将其看成254来进行的,也就是说计算机在运算的时候是没有负数的,全按照正数来处理,但因为有模的存在,这样是合理的!
3、补码的实现。有了上述的概念,求解一个数的补码表达就很容易了。如果是正数,则就是其二进制代码本身,如果是负数,求解的是等价的大正数的二进制码。
例:在8位计算机数的范围下,[+73]补=01001001,[–73]补=[256-73]补=100000000-01001001=10110111,或者直接将183转换为二进制也可以。
因为需要不停地判断借位,或者求一个较大的正数的二进制,所以负数的补码求解起来比较麻烦,但只要稍微花一点技巧就可以很轻松了。
例:[–73]补=[256-73]补=[255-73+1]补=11111111-01001001+1=10110110+1=10110111
这样做的好处就是不再需要考虑借位的问题,而且用1作为被减数的话,就等价于把减数各位取反而已。(因为1-1=0,1-0=1)
所以我们得到了最终的补码表示求解规则:对正数而言,补码与真值相同;对负数而言,所有各位取反加1。当然不得不再提示一句,补码的表示和模的大小是密切相关的,不同的模下面得到的结果往往并不相同。
例:假设n=8, 求-36的补码。 第1步:将36表示成二进制数:00100100 第2步:符号位取1,其余各位取反得11011011 第3步:末位加1,结果为11011100
例:假设n=16, 求-36的补码。 第1步:将36表示成二进制数:00000000 00100100 第2步:符号位取1,其余各位取反得11111111 11011011 第3步:末位加1,结果为11111111 11011100
4、如果有了补码,如何反过来求解真值呢?
如果补码的最高位为0,则表示该数是一个正数,直接将2进制转换为10进制即可;如果补码的最高位为1,则表示该数是一个负数,求解办法其实和前面是类似的,将所有各位取反加一,再转换为10进制,当然别忘了最前面加上负号。
例:求解八位的二进制补码(1000 0001)补、(1000 0000)补、(1111 1111)补、(1111 1110)补对应的十进制真值。 (1000 0001)补 = -(0111 1110 + 1)= - 0111 1111 = -127 (1000 0000)补 = -(0111 1111 + 1)= - 1000 0000 = -128 (1111 1111)补 = -(0000 0000 + 1)= - 0000 0001 = -1 (1111 1110)补 = -(0000 0001 + 1)= - 0000 0010 = -2