机器数和真值
机器数
一个数在计算机中的二进制表示形式叫做这个数的机器数
。机器数是带符号的,计算机用一个数的最高位来存放符号,正数为0
,负数为1
。
例如十进制数+3
,假设计算机的字长为8
位,转换成二进制就是0000_0011
;如果是-3
,就是1000_0011
。那么,这里的0000_0011
和1000_0011
就是机器数。
真值
因为第一位是符号位,所以机器数的形式值不一定等于真正的数值。例如有符号数1000_0011
,最高位1
代表负,其真正的数值是-3
,而不是形式值131
。为了进行区别,将带符号位的机器数对应的真正数值称为机器数的真值
。
例如,0000_0001
的真值为+000_0001 = +1
,1000_0001
的真值为-000_0001 = -1
。
原码、反码和补码
原码
原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值:
[+1]原 = 0000_0001
[-1]原 = 1000_0001
因为第一位是符号位,所以8
位二进制数的取值范围是[1111_1111, 0111_1111]
,即[-127, 127]
。
反码
反码的表示方法如下:
- 正数的反码是其本身。
- 负数的反码是在其原码的基础上,符号位不变,其余各个位取反。
[+1] = [0000_0001]原 = [0000_0001]反
[-1] = [1000_0001]原 = [1111_1110]反
补码
补码的表示方法如下:
- 正数的补码就是其本身。
- 负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后
+1
。
[+1] = [0000_0001]原 = [0000_0001]反 = [0000_0001]补
[-1] = [1000_0001]原 = [1111_1110]反 = [1111_1111]补
编码原因
对于正数,这三种编码方式的结果都相同:
[+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 = 1 + (-1) = [0000_0001]原 + [1000_0001]原 = [0000_0001]反 + [1111_1110]反 = [1111_1111]反 = [1000_0000]原 = -0
结果发现的真值部分是正确的,而唯一的问题其实就出现在0
上,会有[0000_0000]原
和[1000_0000]原
两个编码表示0
。
补码的出现解决了这个问题:
1 - 1 = 1 + (-1) = [0000_0001]原 + [1000_0001]原 = [0000_0001]补 + [1111_1111]补 = [0000_0000]补 = [0000_0000]原
这样可以用[0000_0000]
来表示0
。
补码可以用[1000_0000]
来表示-128
:
(-1) + (-127) = [1000_0001]原 + [1111_1111]原 = [1111_1111]补 + [1000_0001]补 = [1000_0000]补
-1 - 127
的结果应该是-128
,所以在用补码运算的结果中,[1000_0000]补
就是-128
。