计算机存储数字都是存储的二进制补码,以方便进行减法的运算。

正数的原码、反码、补码相等。

负数的原码:最高位1,其余位为该数的数值部分的二进制表示。

负数的反码:负数原码的符号位不变,其余位取反。

负数的补码:负数反码加1。

已知char a=-1,如何快速求出-1在计算机中存储的补码呢?

已知int b=-1,如何快速求出-1在计算机中存储的补码呢?

我们知道,在计算机中,求b-a相当于b+(-a),等于b加上a的补码。这是为什么呢? 现在我们思考一个问题,假设时钟(12小时制)现在的时间是6点钟,我们要想回到2点钟,可以将时钟逆时针往回拨4小时,或者将时钟往顺时针方向拨8小时。即6-2=(6-2+12)%12=(6+8)%12,计算机由于其存储数据的溢出特性,其减去一个数等于加上相应负数的补码其道理就跟这里的时钟是一样的。对于时钟来说,模为12,6减去一个数-4等于加上-4的补码8,这里的8就是用模12减去4得到的。

所以现在我们可以回答上面的问题了,由于a为char型占一个字节,故在计算机中的模应该为2的8次方等于128,用模减去-1就可以得到,-1在计算中存的补码为255,即1111 1111。(虽然char型数据最高位为符号位,取值范围为-128到+127,但是取模仍然是2的8次方)

由于b为int型占4个字节,故在计算机中的模应该为2的32次方,用模减去-1就可以得到,-1在计算中存的补码为1111 1111 1111 1111 1111 1111 1111 1111。

现在我们来验证一下,设char c=-34,原码为1010 0010,反码为1101 1101,补码为1111 1110。直接用模256-34=222,转化为二进制则为1101 1110。

通过上面的例子我们可以知道,已知一个负数及其类型,如何快速求出其补码。下面,我们来思考如何在已知补码的情况下快速求出该负数的十进制值呢?

其实,根据负数求补码和根据补码求负数两个完全是相反的情形。我们还是从上面的时钟问题出发,已知补码为8,如何求得相应的负数-4呢?很容易就知道用8-12=-4,即直接用补码减去模得到的负数就是我们要求得结果。故同理有,我们直接用二进制补码减去相应得的就可以了。比如,设一个char型数据a,其补码为1111 1111,其模应该是2的8次方,用二进制表示即为(1111 1111+00000001),由补码减去模很容易就知道为-1了,但是模都比补码要大,以补码减去模不方便,故我们直接用模减去补码,在加上个负号就行了。 再举个例子,设一个char型数据补码为1101 1011(因为该补码的最高位为1,故可知其为负数),用模(11111111+1)-11011011=0010 0101,该二进制数转化为十进制为37,再加上个负号结果就为-37。

综合以上,负数转换成补码,其步骤为用模加上该负数,再转换成二进制数。 (最高位为1的)补码转换成负数,用模减去补码,将得到的二进制数转换成十进制数,再加上符号就可以了。

最后,需要提醒一下大家的是,由于表达式的整型计算是要在cpu内的相应运算器件内执行,cpu的整型运算器的操作字节长度一般为int型,故对于两个char型的数据运算来说就会发生整型提升,整型提升有如下规则:

如果是有符号char型,则最高位为1时需在补码前全部补1补够32位,最高位为0时需在前面全部补0提升至32位。

如果是无符号char型,则在前面全部补0。

所以,我们需要注意char型数据在发生整型提升时的实际二进制补码。 例如,char a=-128,则其二进制补码位256-128=128,转换成二进制补码结果为1000 0000,发生整型提升,实际的二进制补码结果就为11111111 11111111 11111111 10000000。该过程等价于对原码10000000 00000000 00000000 10000000(32位下的负128)求其补码,即先求反码11111111 11111111 11111111 01111111,再求补码11111111 11111111 11111111 10000000,又等价于对-128求在模为2的32次方下的补码。

最后,总结可知,无论是char型数据还是int型数据,如果是正数,则在32位下的补码就是二进制原码。如果是负数,就求该负数在模为2的32次方下的补码。

最后补充一下,若有补码1000 0000,则当作有符号数时,其解释为-128,当作无符号数时,其解释为128。若有补码1111 1111,当作有符号数时,解释为-1,当作无符号时解释为255。也就是说,从不同的角度来解释内存中的信息,会得到不同的结果。