首先我们来了解下补码的定义,在很多资料上说补码都是从原码说起,但实质上补码是有其定义的:
补码定义:计算机中二进制形式的补数。
这个定义是比较抽象的,下面我将举一些实际的例子来解释。
二进制形式:就是0和1组成的串,例如数字3的二进制形式是11,数字-9的二进制形式是11001。
补数:初中时我们学过互补角,两个角加起来等于180度,则称两个角互补。在日常生活中,将某物体顺时针旋转270度和逆时针旋转90度能达到同样的效果,把时钟里的分钟顺时针调整40分钟和逆时针调整20分钟,分针最后的位置是一样的。这时270是90的补数,90也是270的补数;40和20也同理。
那么计算机中为什么要用补码呢?
因为使用补码可以把减法运算变成加法运算,以此来简化逻辑算术单元设计。现在的计算机里只有加法器,没有减法器。例如7-3可以转换为7+(-3)。为进一步理解,我们再来了解两个定义。
补码计算法定义:非负数的补码是其原码本身;负数的补码是其绝对值的原码最高位符号位不变,其它位取反,再加1。
模定义:一个负整数的绝对值与负整数补码的和。
前面提到的270+90=360,360就是模,40+20=60,60就是模。模其实就是计量范围,在数学计算中就是进位的那一位,像个位数计算3+7=10,这个10就是超出了个位数的计量范围,只能进位。在二进制数中,当位数为n时,模为。
在二进制位数n为4时,7的原码是0111,补码是0111;
-3的绝对值3的原码是0011,再对其原码求补码得到1101,所以-3用二进制形式为1101。
将两数补码相加,得到0100,换成十进制是4,结果正确。
0111
+ 1101
------------
0100
这里我们注意到两二进制数相加结果为10100,最高位的1因为二进制位数的限制为4,所以被丢弃了。10100=00100+10000,被丢弃是10000,即-16。
我们再根据模的定义得知模等于-3和其补码的和,即模=0011+1101=10000,即-16。
我们再来看-3的补码1101,如果将其当成无符号数来看,再最前面加个0即可当成无符号数,得到01101,转换成十进制得其值为13,此时我们发现7-3的本质是转换成了7+13-16,而-16不是真正的减16,而是丢弃,所以这个式子中就只存在一个加法7+13,这就是计算机把减法转换成加法的本质。
最后再来看看原码的补码为什么取反后要加1,如果不加1,那原码-3(1011)取反后就是1100,不看最高位符号位,我们发现011+100=111,即7,而模为8,也就是说当所有位都为1时还比模少了1,所以最后要加上1。
顺带提一下为什么各数据类型的取值范围负数的绝对值比正数大1,就拿byte来说,其位数为8,最小值是-128(10000000),最大值是127(01111111)。
最大值127是01111111应该很好理解,正数最高位肯定是0,要使数值最大,后面肯定要为1。
最小值-128是10000000。很多人根据最大值127理所当然的想到最小值是-127,而且其二进制为11111111。其实不然,首先11111111不是-127,而是-1,再者,我们来看负数二进制转为十进制的计算方法(任取一个负数10101010):
(-1)x+(0x+1x+0x+1x+0x+1x+0x)
所以,(-1)x加括号里的正数,要使值最小,括号里要为0,所以后,7位要全为0,即10000000。