一、前置概念
计算机底层存储数据的时候使用的是二进制数字,但是计算机在存储一个数字的时候并不是直接存储该数字对应的二进制数,而是存储该数字对应的二进制数的补码。
在了解原码、反码和补码之前,我们要了解机器数和真值的概念。
1)机器数
一个数在计算机的存储形式是二进制数,我们称这些二进制数为机器数,机器数是有符号,在计算机中用机器数的最高位存放符号位,0表示正数,1表示负数。
2)真值
因为机器数带有符号位,所以机器数的形式值不等于其真实表示的值(真值),以机器数1000 0001为例,其真正表示的值(首位为符号位)为-1,而形式值(首位就是代表1)为129;因此将带符号的机器数的真正表示的值称为机器数的真值。
二、原码、反码与补码
1)原码
原码的表示与机器数真值表示的一样,即用第一位表示符号,其余位表示数值。也就是说
正数:就是它对应的二进制数。
负数:将绝对值对应的二进制最左边位变为1。
例如的十进制的的正负1,用8位二进制的原码表示如下:
[+1] = 原:[ 0000 0001 ]
[-1] = 原:[ 1000 0001 ]
2)反码
正数 : 和原码相同。
负数 : 在其原码的基础上,符号位不变,其余各位取反。
[+1] = 原:[ 0000 0001 ] = 反:[ 0000 0001 ]
[-1] = 原:[ 1000 0001 ] = 反:[ 1111 1110 ]
3)补码
正数 : 补码是其原码本身。
负数 : 补码是在其原码的基础上,符号位不变,其余各位取反后加1(即在反码的基础上加1)。
[+1] = 原:[ 0000 0001 ] = 反:[ 0000 0001 ] = 补:[ 0000 0001 ]
[-1] = 原:[ 1000 0001 ] = 反:[ 1111 1110 ] = 补:[ 1111 1111 ]
三、数据在计算机中的存储形式
计算机实际上只存储补码,所以说原码转换为补码的过程,也可以理解为数据存储到计算机内存中的过程。
在原、反、补码中,正数的表示是一模一样的,而负数的表示是不相同的,所以对于负数的补码来说,我们是不能直接用进制转换将其转换为十进制数值的,因为这样是得不到计算机真正存储的十进制数的,所以应该将其转换为原码后,再将转换得到的原码进行进制转换为十进制数(机器数包含符号位)
四、为什么会使用原码、反码、补码
对于人脑来说,知道机器数的第一位是符号位是一件很轻松的事情,但对于计算机基础电路设计来说判别第一位是符号位是非常难和复杂的事情,为了让计算机底层设计更加简单,于是设计将符号位参与运算,并且只保留加法的方法,通过加上一个负数的方式来实现减法。这样让计算机运算更加简单,并且也让符号位参与到运算中去。
五、使用原码、反码与补码进行运算
1)使用原码运算
计算十进制表达式:1-1=0
1 - 1 = 1 + (-1)
= 原:[ 0000 0001 ] + 原:[ 1000 0001 ]
= 原:[ 1000 0010 ] = -2
结论:如果用原码表示,让符号位也参与计算,对于减法来说,结果是不正确的。这也是计算机内部在存储数据时不使用原码的原因,为了解决这一问题,出现了反码。
2)使用反码运算
计算十进制表达式:1-1=0
1 - 1 = 1 + (-1)
= 原:[ 0000 0001 ] + 原:[ 1000 0001 ]
= 反:[ 0000 0001 ] + 反:[ 1111 1110 ]
= 反:[ 1111 1111 ] = 原:[ 1000 0000 ] = -0
结论:通过计算我们发现用反码计算减法,结果的真值部分是正确的。而唯一的问题出现在"0"这个特殊的数值上,虽然人们理解上+0和-0是一样的,但是0带符号是没有任何意义的,而且会有[0000 0000]原和[1000 0000]原两个编码表示0。为了解决这一问题,出现了补码。
3)使用补码运算
计算十进制表达式:1-1=0
= 原:[ 0000 0001 ] + 原:[ 1000 0001 ]
= 补:[ 0000 0001 ] + 补:[ 1111 1111 ]
= 补:[ 0000 0000 ] = 原:[ 0000 0000 ] = 0
结论:这样0用[0000 0000]表示,而以前出现问题的-0则不存在了,而且人们还发现可以用[1000 0000]表示-128,-128的推算过程如下:
(-1) + (-127) = -128
= 原:[ 1000 0001 ] + 原:[ 1111 1111 ]
= 补:[ 1111 1111 ] + 补:[ 1000 0001 ]
= 补:[ 1000 0000 ]
注意:因为实际上是使用以前的-0的补码来表示-128,所以-128并没有原码和反码表示,只要补码是[1000 0000],其十进制数值就为-128。
4)小结
因为补码能多存储一个-128,而且在计算机底层中存储的是补码,所以在计算机中一个8位的二进制数的存储范围是用补码表示的[-128,127],而不是用原码或反码表示的[-127,127]。这也可以解释为什么计算机中一个字节的取值范围是[-128,127]。
六、总结(牢记)
二进制的最高位是符号位:0表示正数,1表示负数。
正数的原码反码补码都一样,三码合一。
负数的反码 = 它的原码符号位不变,其它位取反。
负数的补码 = 它的反码 + 1, 负数的反码 = 负数的补码 - 1 。
0 的反码、补码都是 0 。
在计算机运算的时候都是以 “补码” 的方式来运算的。
当我们看运算结果的时候,要看它的原码(重点)。