计算机中的数值是用二进制来存储的,这个叫机器数。而这种存储的二进制数值,用最位代表符号位(+、-),正数为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