0%

原码反码补码

约翰·冯·诺依曼(John von Neumann,1903年12月28日-1957年2月8日),一般简称冯·诺依曼,美籍匈牙利数学家、计算机科学家、物理学家,是20世纪最重要的数学家之一。冯·诺依曼是布达佩斯大学数学博士,在现代计算机、博弈论、核武器和生化武器等领域内的科学全才之一,被后人称为“计算机之父”、“博弈论之父”。

一、概念

  1. 机器数:一个数在计算机中的表现形式叫做机器数,它有正负之分。在计算机中用一个数的最高位(符号位)用来表示它的正负,其中0表示正数,1表示负数。

    假设计算机字长为8位,正数2的二进制数来是00000010,而负数-2则用10000010表示,这里的0000001010000010是机器数。

    • 在同一时间中处理二进制数的位数叫字长。
    • 计算机字长是指计算机中CPU在一次操作中能处理的单位字的长度,即运算器能够并行处理和存储器每次读写操作时能包含的二进制码的位数,常见有8、16、32、64位字长。
  2. 真数:计算机中的机器数对应的真实的值就是真数,也叫真值。对最高位(符号位)后面的二进制数转换成十进制,并根据最高位来确定这个数的正负。

    对于上面的0000001010000010来说,不考虑最高位的值,转换成十进制分别是2-2,即其真数分别是2-2

  3. 原码:用第一位表示符号,其余位表示值。

    • 因为第一位是符号位,所以8位二进制数的取值范围就是:[1111 1111, 0111 1111],即[-127, 127]
    • 原码是容易被人脑所理解的表达方式
  4. 反码:正数的反码是其本身,负数的反码是符号位保持不变,其余位取反。

    • 正数1的原码是00000001,它的反码是其本身00000001
    • 负数-1的原码是10000001],其反码是11111110
  5. 补码:正数的补码是其本身,负数的补码是在其反码的基础上+1

    • 正数1的原码是00000001,它的补码是其本身00000001
    • 负数-1的原码是10000001,其反码是11111110,其补码是11111111

二、为什么引入反码补码

  1. 人脑可以知道第一位是符号位,在计算的时候我们会根据符号位选择对真值区域的加减。计算机如要辨别符号位显然会让计算机的基础电路设计变得十分复杂,于是人们想出了将符号位也参与运算的方法。

    • 根据运算法则减去一个正数等于加上一个负数,即:1-1=1+(-1)=0,所以机器可以只有加法而没有减法,这样计算机运算的设计就更简单了。

      于是人们开始探索将符号位参与运算,并且只保留加法的方法。

  2. 探索开始(默认十进制加减)

😁只用原码

1
2
3
4
5
1 - 1 
= 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [1000 0010]原
= -2

如果用原码表示且让符号位也参与计算,对于减法来说结果显然是不正确的,这也就是为何计算机内部不使用原码表示一个数。

😁引入反码:解决了原码做减法的问题

1
2
3
4
5
6
7
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
2
3
4
5
6
7
8
1 - 1
= 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]反 + [1111 1110]反
= [0000 0001]补 + [1111 1111]补
= [0000 0000]补
= [0000 0000]原
= 0

这样0[0000 0000]表示且不存在-0的情况了。

😁-128问题:

1
2
3
4
5
6
-128
= (-1) + (-127)
= [1000 0001]原 + [1111 1111]原
= [1111 1110]反 + [1000 0000]反
= [1111 1111]补 + [1000 0001]补
= [1000 0000]补

在用补码运算的结果中,[1000 0000]补就是-128,实际上是使用以前的-0的补码来表示-128,所以-128并没有原码和反码表示。(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原,这是不正确的)

使用补码,不仅仅修复了0的符号以及存在两个编码的问题,而且还能够多表示一个最低数。

  1. 这就是为什么8位二进制,使用原码或反码表示的范围为[-127, +127],而使用补码表示的范围为[-128, 127]。同理可得MySQL中int有符号型取值范围[-2^31, 2^32-1]

三、参考

  1. 原码、反码、补码