原码、反码、补码和移码
原码、反码、补码 和 移码 是计算机中表示整数(特别是带符号整数)的一些编码方式。它们是为了方便在计算机中处理整数的符号和数值范围而设计的。不同的编码方式有不同的表示规则和数学运算性质。
我们先来了解它们各自的定义和特点,再进行对比。
1. 原码(Sign-Magnitude)
原码 是一种最简单的整数表示方式,它将整数分为符号位和数值部分。
- 符号位:表示数值的正负。一般约定,符号位为 0 表示正数,符号位为 1 表示负数。
- 数值部分:表示该数值的绝对值,用二进制表示。
示例:
对于 8 位原码表示,最高位是符号位,剩余 7 位表示数值。
-
正数
+5
的原码表示:0 0000101 // 符号位 0 表示正数,数值部分表示 5
-
负数
-5
的原码表示:1 0000101 // 符号位 1 表示负数,数值部分表示 5
特点:
- 原码的表示方法简单直观,但其加减法运算较为复杂,需要特别处理符号位。
- 存在两个零的表示:正零(
00000000
)和负零(10000000
)。
2. 反码(One's Complement)
反码 是对原码的改进,主要是为了简化加减运算的过程。在反码表示中,负数是通过对正数的原码进行逐位取反得到的。
- 正数的反码与原码相同。
- 负数的反码通过将原码的每一位取反得到。
示例:
对于 8 位反码表示:
-
正数
+5
的反码表示:0 0000101 // 正数与原码相同
-
负数
-5
的反码表示:1 1111010 // 负数反码是原码逐位取反
特点:
- 反码可以方便地进行加减法运算,但仍然存在两个零的表示:正零(
00000000
)和负零(11111111
)。 - 加法和减法运算时需要特别处理符号位。
3. 补码(Two's Complement)
补码 是最常用的整数表示法,它解决了反码存在的两个零问题,并且简化了加减法运算。补码的表示规则是:
- 正数的补码与原码相同。
- 负数的补码通过对反码加 1 得到。
示例:
对于 8 位补码表示:
-
正数
+5
的补码表示:0 0000101 // 正数与原码相同
-
负数
-5
的补码表示:- 先求原码:
10000000
表示 -128(最小负数) - 求反码:
11111010
- 然后加 1 得到补码:
11111011
。
1 1111011 // 负数补码为原码的反码 + 1
- 先求原码:
特点:
- 补码是目前计算机中最常用的表示法,尤其在 CPU 的算术运算中。
- 唯一的零表示:
00000000
表示零,消除了原码和反码中出现的两个零问题。 - 由于补码可以直接用于加法和减法运算,因此硬件实现更高效。
- 负数的补码表示范围比原码和反码要大。比如,8 位补码可以表示的范围是从
-128
到127
。
4. 移码(Excess-K or Bias)
移码 是一种常用于表示浮点数的编码方法,也可以用于整数的表示。移码将整数值 X
转换为偏移量加上原数值,即通过将数值加上一个常数偏移量 K
,从而消除符号位。
- 偏移量
K
是根据表示范围来确定的,一般选择K = 2^(n-1) - 1
,其中n
是位数。 - 对于一个数值
X
,它的移码表示为X + K
。
示例:
对于 8 位移码表示,偏移量 K
为 127
,即 2^(8-1) - 1 = 127
。
-
正数
+5
的移码表示:5 + 127 = 132 // 00000101 + 127 -> 132 (10000100)
-
负数
-5
的移码表示:-5 + 127 = 122 // 11110111
特点:
- 移码的优点是它使得零可以只有一个表示(没有正零和负零的困扰)。
- 由于移码与补码的概念类似,因此它的加法运算较为简单,常用于浮点数的指数部分。
对比原码、反码、补码、移码
特性 | 原码 | 反码 | 补码 | 移码 |
---|---|---|---|---|
表示范围 | -128 到 127 | -127 到 127 | -128 到 127 | 0 到 2^(n-1) - 1 |
零的表示 | 正零和负零 | 正零和负零 | 唯一的零 | 唯一的零 |
符号位 | 符号位 + 数值部分 | 符号位 + 反码 | 符号位 + 补码 | 移码值(加偏移量) |
加法/减法 | 需要特殊处理 | 需要特殊处理 | 可以直接运算 | 可以直接运算 |
运算复杂性 | 高 | 高 | 低 | 低 |
总结
- 原码:简单直观,但加减法运算复杂,存在两个零的表示。
- 反码:简化了加法运算,但仍然存在两个零的问题。
- 补码:最常用的表示方式,简化了加法和减法的运算,同时消除了两个零的问题。
- 移码:通常用于浮点数表示,使用一个偏移量来消除符号位,简化运算。
补码是最常见的表示方式,尤其在计算机硬件中,几乎所有的计算都是基于补码运算进行的。