原码、反码、补码

221 阅读6分钟

本文学习计算机的原码, 反码和补码.。介绍、为何使用、计算机中的使用。

说明以下都以八位举例。

机器码

机器码即是一个数在计算机中的表现形式。在计算机中,它的世界只有 0和1,对于符号的表示方式:最高位为1则表示这个数为负数、为0则表示这个数为正数。

对于十进制 +5,对应机器码为:0000 0101

对于十进制 -6,对应机器码为:1000 0110

这里的+5 、-6 即是真值。0000 0101、1000 0110为机器码。


原码、反码、补码

  • 原码

    原码就是符号位加上真值的绝对值,也就是机器码。

    原码也是我们可以理解的。

    [+10]^原 = 0000 1010

    [-5]^原 = 1000 0101

    范围:由于首位为符号位,所以其表示范围为:

    【1111 1111 ,0111 1111】

    对应十进制

    【-127,127】

  • 反码

    正数的反码就是其本身。负数的反码就是在原码的基础上符号位不变,其余各位取反。

    对于反码,正数我们还能看得懂,但是对于负数得先转换为原码再计算。

    [+10]^反= 0000 1010

    [-5]^反 = 1111 1010

    范围: 【-127,127】

  • 补码

    正数的补码就是其本身。负数的补码就是在反码的基础上加一。

    对于补码,正数我们还能看得懂,但是对于负数得先转换为反码再转换为原码再计算。

    [+10]^补= 0000 1010

    [-5]^补 = 1111 1011

【-128,127】


为何有原码、反码、补码

对于正数原码、反码、补码都相同,无需解释。

【+10】=【0000 1010】原=【0000 1010】反=【0000 1010】补

但是对于负数。这三个码是不同的,那么有什么作用呢?

【-5】=【1000 0101】原=【1111 1010】反=【1111 1011】补

原码的出现使得计算机有方式将符号位参与运算,计算机无需关心符号,只做它的0/1运算即可

但是如果使用原码做数学运算(存在负数)时就会出现问题

对于两个正数做数学运算:

2 + 4 = 6

【0000 0010】^原 + 【0000 0100】^原 = 【0000 0110】^原 = 6

使用原码没有问题。

对于存在负数做数学运算:

4 - 2 = 4 + (-2) = 2

【0000 0100 】^原 + 【1000 0010】^原 = 【1000 0110】^原 = - 6

发现结果无论是符号还是数值都会有问题。

所以!!反码来了

4 - 2 = 4 + (-2) = 2

【0000 0100 】^原 + 【1000 0010】^原 = 【0000 0100 】^反 + 【1111 1101】^反= 【0000 0001】^反 =【0000 0001】^原 = +1

结果是不对的,因为此刻反码计算存在存在进位,导致溢出。

再来一个例子:

1- 1 = 1+(-1) = 0

【0000 0001 】^原 + 【1000 0001】^原 = 【0000 0001 】^反 + 【1111 1110】^反= 【1111 1111】^反 =【1000 0000】^原 = -0

这个例子,这里只有符号问题了。

再来一个例子:

2 - 4 = 2+ (-4) = -2

【0000 0010 】^原 + 【1000 0100】^原 = 【0000 0010 】^反 + 【1111 1011】^反= 【1111 1101】^反 =【1000 0010】^原 = -2

这个结果就是正确的。

再来一个例子:

2 - 6 = 2+ (-6) = -4

【0000 0010 】^原 + 【1000 0110】^原 = 【0000 0010 】^反 + 【1111 1001】^反= 【1111 1011】^反 =【1000 0100】^原 = -4

这个结果也是正确的。

结论

使用反码计算只要不出现进位导致溢出问题,那么计算结果就是正确的(这里只针对加减运算)。也就是负数的绝对值大于正数的绝对值。

补码就来了

4 - 2 = 4 + (-2) = 2

【0000 0100 】^原 + 【1000 0010】^原

= 【0000 0100 】^反 + 【1111 1101】^反

= 【0000 0100 】^补 + 【1111 1110】^补

= 【0000 0010】^补

= 【0000 0010 】^原 = + 2

哎这结果就对了!!!

补码只在反码的基础上加一,为何结果就是正确的呢?通过规律就可以发现,对于两数相加负数的绝对值大于正数的绝对值,使用反码计算得出的结果是正确的,使用补码计算得出的结果,会转为原码,得出的结果也是正确的。对于正数的绝对值大于负数的绝对值时反码的计算结果永远比预期少一,使用补码运算会加一结果当然会正确。

我自己也倒腾了一会:

计算:m+(-n)

首先得出 -n的反码,再加m,也就是 【1111 1111】- n + m

①m<n 【1111 1111】 减去一个大于0的数,也就不会进位,得出的反码转化为源码结果是正确的。

②m = n 【1111 1111】减去0,也就是 本身,转换为原码就是 【1000 0000】 = -0

③ m>n 【1111 1111】 加上一个大于0的数,会出现进位,此刻符号位没错为0表示正数,【1111 1111】+1 = 【0000 0000】,结果永远是少一的,这就是为啥补码会在反码的基础上加一再参与运算的原因。

还有在上面我们提到过,补码的表示范围为 -128 到127,

这个范围也有意思的:

原码补码
0111 11110111 1111+127
0111 11100111 1110+126
........
0000 00000000 00000
1000 00011111 1111-1
1000 00101111 1110-2
补码不断减一
1111 11111000 0001-127
无法表示1000 0000-128

这也就约定了,在计算机中 使用【1000 0000】补,来表示-128,并且-128没有原码和反码的表示。而且还解决了上面提到的【1000 0000】表示-0的问题,顺带使得补码的表示范围扩充了一位。

同样的对于int类型他的表示范围为

原码、反码:【-232 -1 , 232-1】

补码:【-232 , 232-1】