基础03:原码、反码、补码

本文介绍原码、反码、补码,以及为什么要使用补码。需要了解数学的取模运算。

机器数与真值

机器数,即数字在计算机中的二进制表示形式。
真值,第一位用+-表示数字的正负,其余为二进制数。
举个栗子:-3的机器数是10000011,真值是-0000011。

原码

原码,符号位加真值的绝对值。

1
2
+3[原] = 00000011
-3[原] = 10000011

8位二进制数原码的取值范围是[11111111, 01111111],即[-127, 127]

反码

正数的反码是其原码。
负数的反码,符号位不变,其余各位取反,即1变成0,0变成1。

1
2
+3[反] = 00000011[原] = 00000011[反]
-3[反] = 10000011[原] = 11111100[反]

8位二进制数反码的取值范围是[11111111, 01111111],即[-127, 127]

补码

正数的的补码是其原码。
负数的补码,是其反码+1。

1
2
+3[补] = 00000011[原] = 00000011[反] = 00000011[补]
-3[反] = 10000011[原] = 11111100[反] = 11111101[补]

反码和补码均不能直接看出其实际的数值,需要转换成原码后再计算。

为何要使用补码

原码比较直观,它的数值部分就是该数的绝对值,而且与真值、十进制数的转换十分方便。但是它的加减法运算较复杂。当两数相加时,机器要首先判断两数的符号是否相同,如果相同则两数相加,若符号不同,则两数相减。在做减法前,还要判断两数绝对值的大小,然后用大数减去小数,最后再确定差的符号。换言之,用这样一种直接的形式进行加运算时,负数的符号位不能与其数值部分一同参加运算,而必须利用单独的线路确定和的符号位。要实现这些操作,电路就很复杂。
为了减少设备,解决机器内负数的符号位参加运算的问题,总是将减法运算变成加法运算,引进了反码机器数,可以让符号位直接参与计算,把它统一看做无符号数。

1
-3 + 2 = 11111100[反] + 00000010[反] = 11111110[反] =10000001[原] = -1

看似挺好,但也会出问题。

1
3 - 2 = 3 + (-2) = 00000011[反] + 11111101[反] = 00000000[反] = 00000000[原] = 0

显然是不对的。
反码可以让符号位直接参与运算,但计算结果有错误。
并且,11111111[反] = 10000000[原] = -0 00000000[反]=00000000[原] = +0
自然数中, -0 = +0 = 0,但是0却又两个表示。
所以,反码充满了错误。

为了解决反码的错误,引入了补码。

1
2
3
-3 + 2 = 11111101[补] + 00000010[补] = 11111111[补] = 11111110[反] = 10000001[原] = -1
3 + (-2) = 00000011[补] + 11111110[补] = 00000001[补] = 00000001[原] = 1
1 + (-1) = 00000001[补] + 111111111[补] = 00000000[补] = 00000000[原] = 0

即,0 可以用00000000[补]表示,-0不存在。用10000000[补]表示-128。

1
(-1) + (-127) = 11111111[补] + 10000001[补] = 10000000[补] = -128

注:-1 + -127的结果是-128,所以用补码最后计算的结果10000000[补]来表示-128,但-128并不存在反码和原码。若按照反码和原码计算,10000000[补] = 01111111[反] = 00000000[原] = 0显然是不正确的。
使用了补码,可以再[-127, 127]的范围内,在表示-128,即可以表示的范围是[-128, 127]。
所以,n位二进制数,可表示的整数范围是[-2^n-1, (2^n-1) - 1]。上述的栗子n=8,即一个字节。

取模(mod)

正数取模,易于理解。

1
5 mod 3 = 2

负数取模,要理解取模运算的数学定义。

1
x mod y = x - y * floor(x/y)

其中floor(x)称为向下取整函数,表示不超过x的最大整数。
举个栗子:

1
-5 mod 3 = -5 - 3 * floor(-5 / 3) = -5 - 3 * floor(-1.6666...)= -5 - 3 * (-2) = 1

所以-5 mod 3 = 1

同余

若x mod z = y mod z,那么称x, y关于z同余,记为 x ≡ y (mod z)。
同余有很多定理,与本文没有关系,有兴趣的童鞋自己去证明或查资料。

补码的数学原理

先说结论:补码对应的无符号整数与真值是关于256(=2^8)同余。
正数和0的补码对应的无符号整数等于其真值,所以也同余。
关于负数,举个栗子。
-3 = 11111101[补] 而11111101作为无符号二进制的值是253。
-3 mod 256 = -3 - 256 * floor(-3/256) = -3 - 256 * (-1) = 253
253 mod 256 = 253
所以 -3 ≡ 253 (mod 256)。
进一步的结论,在8位机中,计算机的循环计数周期为256,符号位参与运算,即将其当做无符号数进行运算后的结果,实际是把真值对256取模。在原码、反码、补码中,只有补码对应的无符号数与真值是关于256同余的,所以用补码的形式表示数字是符合数学原理的。

总结

  1. 原码即数值的二进制本身,最高位表示符号位,0为正数,1为负数。
  2. 正数的反码为其原码,负数的反码,除符号位外,其余各个位取反。
  3. 正数的补码为其原码,负数的原码,为反码+1。
  4. 补码的取值范围是[-2^n-1, (2^n-1) - 1],可以表示最多的整数,而且符号位参与运算不会出错。
  5. 补码的数学解释是补码的无符号二进制数与补码的真值关于2^n同余。

如果本文对你有所帮助,请小额赞助
~~ EOF ~~