Bootstrap

原码、反码和补码

机器数和真值

机器数

  一个数在计算机中的二进制表示形式叫做这个数的机器数。机器数是带符号的,计算机用一个数的最高位来存放符号,正数为0,负数为1
  例如十进制数+3,假设计算机的字长为8位,转换成二进制就是0000_0011;如果是-3,就是1000_0011。那么,这里的0000_00111000_0011就是机器数。

真值

  因为第一位是符号位,所以机器数的形式值不一定等于真正的数值。例如有符号数1000_0011,最高位1代表负,其真正的数值是-3,而不是形式值131。为了进行区别,将带符号位的机器数对应的真正数值称为机器数的真值
  例如,0000_0001的真值为+000_0001 = +11000_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. 正数的补码就是其本身。
  2. 负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+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

;