原码、反码、补码详解

机器数和真值

计算机中的数值是用二进制来存储的,这个叫机器数。而这种存储的二进制数值,用最位代表符号位(+、-),正数为0,负数为1。

现用一字节(即8位)来表示数值,比如:

[+1] = [0000 0001]
[-1] = [1000 0001]

原码、反码、补码

  • 原码

    原码便是我们日常生活中的十进制,转化为二进制数,并添加符号位。

    [+1] = [0000 0001]
    [-1] = [1000 0001]

  • 反码

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

    [+1] = [0000 0001] = [0000 0001]
    [-1] = [1000 0001] = [1111 1110]

  • 补码

    正数的补码是其本身,负数的补码是在原码的基础上,符号位不变,区域各位取反,最后再+1,即是在反码的基础上+1。

    [+1] = [0000 0001] = [0000 0001] = [0000 0001]
    [-1] = [1000 0001] = [1111 1110] = [1111 1111]

为何要使用原码、反码、补码

首先,因为人很容易通过二进制数值最高位辨别出这个数是不是负数,进而进一步计算。但对于计算机来说这种辨别符号位的设计是非常复杂的,于是人们想出了将符号位也参与运算的方法. 我们知道,根据运算法则减去一个正数等于加上一个负数,即:1 - 1 = 1 + (-1),这样就使得计算机只需要用加法就可以解决计算问题。

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

  • 原码计算

    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”这个特殊的数值上。虽然人们理解上+0和-0是一样的,但是0带符号是没有任何意义的。而且会有 [0000 0000] 和 [1000 0000] 两个编码表示0。为了解决这个问题,设计出了补码。

  • 补码计算

    1 - 1 = 1 + (-1) = [0000 0001] + [1000 0001] = [0000 0001] + [1111 1111]= [0000 0000] = [0000 0000] = 0。

    补码相加后,会出现9位,但是一字节只能存储8位,多出来的那位属于溢出,就自动去掉了。于是就解决了-0的问题。

    由此也引出了一个字节能存储数值的范围问题,正数的最大值为 [0111 1111] = 127,而负数的最小值为[1111 1111] = -127。而书上看到的范围是 [-128,127],实际上是用-0来替代-128。

    (-1) + (-127) = [1000 0001] + [1111 1111] = [1111 1111] + [1000 0001]= [1000 0000]

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

All content under CC BY-NC-ND 4.0