原码,反码,补码一文速通
机器数:万物之基
就是二进制数,这些而二进制数能够被机器理解并执行。
机器数带有符号,计算机字长为8位,所以最高位代表符号,正数是0,负数是1,例如0000 0011就表示+3,1000 0011就代表-3。 以上的0000 0011就是机器数。
真值
带符号位的机器数对应的十进制数就是机器数的真值。例如: 0000 0011=+000 0011=+3
原码
即最基本的使用二进制代表十进制,是人脑最容易理解的表示方式。
[+1]原=0000 0001
第一位不表示值,只表示正负。
[1111 1111]代表-127
注:原码的0有两种表示形式:0000 0000和1000 0000
反码
正数的反码是其本身;
负数的反码是在其原码的基础上,符号位不变,其余各个位取反。
[+1] = [0000 0001]原= [0000 0001]反
[-1] = [1000 0001]原= [1111 1110]反
如果一个反码表示的是负数,人脑****无法直观的看出来它的数值。通常要将其转换成原码再计算。
注:0的反码也有两种:0000 0000和1111 1111
补码
正数的补码还是其本身;
负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1。(也即在反码的基础上+1)
[+1] = [0000 0001]原= [0000 0001]反= [0000 0001]补
[-1] = [1000 0001]原= [1111 1110]反= [1111 1111]补
原码,反码,补码是表示同一个数字的三种不同形式。
为什么要有补码和反码?
计算十进制的表达式: 1 - 1 = 0
1 - 1 = 1 + (-1) = [0000 0001]原+ [1000 0001]原= [1000 0010]原= -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。
于是补码的出现,解决了0的符号问题以及0的两个编码问题:
1-1 = 1 + (-1) = [0000 0001]原+ [1000 0001]原= [0000 0001]补+ [1111 1111]补= [1 0000 0000]补=[0000 0000]补=[0000 0000]原注意:进位1不在计算机字长里。
这样0用[0000 0000]表示,而以前出现问题的-0则不存在了。而且可以用[1000 0000]表示-128:-128的由来如下:
(-1) + (-127) = [1000 0001]原+ [1111 1111]原= [1111 1111]补+ [1000 0001]补= [1000 0000]补
-1-127的结果应该是-128,在用补码运算的结果中,[1000 0000]补就是-128,但是注意因为实际上是使用以前的-0的补码来表示-128,所以-128并没有原码和反码表示。(对-128的补码表示[1000 0000]补,算出来的原码是[0000 0000]原,这是不正确的)
使用补码,不仅仅修复了0的符号以及存在两个编码的问题,而且还能够多表示一个最低数。这就是为什么8位二进制,使用原码或反码表示的范围为[-127, +127],而使用补码表示的范围为[-128, 127]。
因为机器使用补码,所以对于编程中常用到的有符号的32位int类型,可以表示范围是: [-231, 231-1] 因为第一位表示的是符号位,而使用补码表示时又可以多保存一个最小值。