在学习原码、反码、补码之前,需要先了解机器数和真值的概念。
机器数
- 一个数在计算机中的二进制表示形式,叫做这个数的机器数。
- 机器数是带符号的,在计算机用机器数的最高位存放符号,正数为0,负数为1。
- 十进制中的数 +3 ,计算机字节为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。
- 那么,这里的 00000011 和 10000011 就是机器数。
真值
- 因为第一位是符号位,所以机器数的形式值就不等于真正的数值。
- 例如有符号数 10000011,其最高位1代表负,其真正数值是 -3,而不是形式值131。
- 将带符号位的机器数对应的真正数值称为机器数的真值。
- 00000001的真值 = +0000001 = +1,10000001的真值 = –000 0001 = –1
原码
对于一个数,计算机要使用一定的编码方式进行存储,原码、反码、补码是机器存储一个具体数字的编码方式。
原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值。
00000001 => 1
01111111 => 127
10000001 => -1
11111111 => -127
反码
- 正数的反码是其本身;
- 负数的反码是在其原码的基础上,符号位不变,其余各个位取反。
+1 原码:00000001
+1 反码:00000001
+127 原码:01111111
+127 反码:01111111
-1 原码:10000001
-1 反码:11111110
-127 原码:11111111
-127 反码:10000000
可见如果一个反码表示的是负数,人脑无法直观的看出来它的数值。通常要将其转换成原码再计算。
补码
- 正数的补码就是其本身;
- 负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1。(也即在反码的基础上+1)
+1 原码:00000001
+1 反码:00000001
+1 补码:00000001
+127 原码:01111111
+127 反码:01111111
+127 补码:01111111
-1 原码:10000001
-1 反码:11111110
-1 补码:11111111
-127 原码:11111111
-127 反码:10000000
-127 补码:10000001
对于负数,补码表示方式也是人脑无法直观看出其数值的。通常也需要转换成原码再计算其数值。
为什么使用原码、补码、反码
+1的原码:00000001
+1的反码:00000001
+1的补码:00000001
-1的原码:10000001
-1的反码:11111110
-1的补码:11111111
-
原码做加减
原码做加法 1+1=1 原00000001 => 真1 原00000001 => 真1 原00000010 => 真2 原码做减法 1+(-1)=0 原00000001 => 真1 原10000001 => 真-1 原10000010 => 真-2
如果用原码表示,让符号位也参与计算,显然对于减法来说,结果是不正确的。这也就是为何计算机内部不使用原码表示一个数。
-
反码做加减
反码做加法 1+1=1 反00000001 => 原00000001 => 1 反00000001 => 原00000001 => 1 反00000010 => 原00000010 => 2 反码做减法 1+(-1)=0 反00000001 => 原00000001 => 1 反11111110 => 原10000001 => -1 反11111111 => 原10000000 => -0
发现用反码计算减法,结果的真值部分是正确的。而唯一的问题其实就出现在"0"这个特殊的数值上,虽然人们理解上+0和-0是一样的,但是0带符号是没有任何意义的,而且会有[0000 0000]原和[1000 0000]原两个编码表示0。
-
补码做加减
补码做加法 1+1=1 补00000001 => 反00000001 => 原00000001 => 1 补00000001 => 反00000001 => 原00000001 => 1 补00000010 => 反00000010 => 原00000010 => 2 反码做减法 1+(-1)=0 补00000001 => 反00000001 => 原00000001 => 1 补11111111 => 反11111110 => 原10000001 => -1 补00000000 => 反00000000 => 原00000000 => 0
这样0用 00000000 表示,而以前出现问题的-0则不存在了。而且可以用[1000 0000]表示-128:
同时为了充分利用资源,就将原来本应该表示“-0”的补码规定为表明-128。这样就可以让有符号数多一个有用的数据点。
这个值不能用普通的取反加1来计算。
而且1000 0000是-128刚好也可以满足基本的运算。
如下:
反码做减法
-1+(-127)=0
补11111111 => 反11111110 => 原10000001 => -1
补10000001 => 反10000000 => 原11111111 => -127
补10000000 => -128