原码反码补码全面解析
原码、反码、补码详解
1. 基本概念与定义
在计算机中,数值以二进制形式存储。为了表示有符号数(正数和负数),发展出了原码、反码和补码三种编码方式。现代计算机系统普遍采用补码作为整数存储和运算的标准。
1.1 机器数与真值
- 真值:带符号的十进制数本身,如
+5、-3。 - 机器数:真值在计算机中的二进制表示形式。其最高位(最左边)为符号位(
0表示正,1表示负),其余位为数值位。
2. 三种编码方式详解
2.1 原码 (Sign-Magnitude)
原码是最直观的表示方法,符号位加上绝对值的二进制形式。
- 定义:最高位为符号位,其余位表示数值的绝对值。
- 表示范围:对于
n位二进制数,范围为[-(2^(n-1)-1), +(2^(n-1)-1)]。例如,8位原码的范围是[-127, +127]。 - 特点:
- 直观,符合人类思维。
- 存在
+0(00000000) 和-0(10000000) 两种零的表示,造成歧义和资源浪费。 - 加减法运算复杂,需要判断符号位,硬件电路设计繁琐。
示例:8位原码表示
| 十进制真值 | 原码(二进制) |
|---|---|
| +5 | ` |
| 0000 0101` | |
| -5 | ` |
| 1000 0101` | |
| +0 | ` |
| 0000 0000` | |
| -0 | ` |
| 1000 0000` |
2.2 反码 (Ones‘ Complement)
反码是为了解决原码运算问题而引入的过渡方案,正数的反码是其本身,负数的反码是其原码符号位不变,数值位按位取反。
- 定义:
- 正数:反码 = 原码。
- 负数:符号位不变,数值位按位取反(
0变1,1变0)。
- 表示范围:与
n位原码相同,[-(2^(n-1)-1), +(2^(n-1)-1)]。 - 特点:
- 同样存在
+0(00000000) 和-0(11111111) 的问题。 - 减法可以转换为加法,但运算后可能产生循环进位,需要额外处理(即“循环进位”加回到最低位),硬件实现仍不完美。
- 同样存在
示例:8位反码表示
| 十进制真值 | 原码 | 反码 |
|---|---|---|
| +5 | ` | |
| 0000 0101` | ` | |
| 0000 0101` | ||
| -5 | ` | |
| 1000 0101` | ` | |
| 1111 1010` |
2.3 补码 (Two‘s Complement)
补码是现代计算机中整数表示的标准方式,它完美解决了原码和反码的问题。
- 定义:
- 正数:补码 = 原码。
- 负数:反码 + 1。等价于:该负数的绝对值对应的二进制数,所有位按位取反后加1。
- 表示范围:对于
n位二进制数,范围为[-2^(n-1), +(2^(n-1)-1)]。例如,8位补码的范围是[-128, +127],比原码和反码多表示一个数-128。 - 核心优势:
- 0的唯一表示:
+0和-0的补码都是00000000,消除了歧义。 - 统一加减法:减法运算可以转换为加法运算,无需额外的硬件判断逻辑。符号位可以像数值位一样参与运算,简化了CPU的算术逻辑单元(ALU)设计。
- 模运算的自然结果:补码的本质是模运算。对于
n位二进制,模为2^n。一个负数X的补码,正是2^n - X的二进制表示。这使得加法器在溢出时,自动实现了模运算的结果。
- 0的唯一表示:
示例:8位补码表示与转换
| 十进制真值 | 原码 | 反码 | 补码 | 计算过程(负数) |
|---|---|---|---|---|
| +5 | ` | |||
| 0000 0101` | ` | |||
| 0000 0101` | ` | |||
| 0000 0101` | - | |||
| -5 | ` | |||
| 1000 0101` | ` | |||
| 1111 1010` | ` | |||
| 1111 1011` | 反码(` | |||
11111010) + 1 = | ||||
| 11111011` | ||||
| +0 | ` | |||
| 0000 0000` | ` | |||
| 0000 0000` | ` | |||
| 0000 0000` | - | |||
| -0 | ` | |||
| 1000 0000` | ` | |||
| 1111 1111` | (1)0000 0000(溢出丢弃) → ` | |||
| 0000 0000` | - | |||
| -128 | 无法表示 | 无法表示 | ` | |
| 1000 0000` | ` | |||
| 128 =2^7`,直接对应补码定义 |
3. 编码方式对比与应用| 特性 | 原码 | 反码 | 补码 |
| :--- | :--- | :--- | :--- |
|正数表示| 符号位0 + 绝对值 | 与原码相同 | 与原码相同 |
|负数表示| 符号位1 + 绝对值 | 符号位不变,数值位取反 | 反码 + 1 |
|零的表示|+0和-0两种 |+0和-0两种 | 唯一 (000...0) |
|表示范围 (n位)| [-(2^(n-1)-1), +(2^(n-1)-1)] | 同原码 | [-2^(n-1), +(2^(n-1)-1)] |
|加减法运算| 复杂,需判断符号 | 可转换,但有循环进位 |统一为加法,最简便 |
|硬件实现| 复杂 | 较复杂 |简单高效|
|现代应用| 基本淘汰 | 基本淘汰 |整数运算标准|
4. 补码运算实例
补码的核心优势在于将减法变为加法。运算时,所有操作数均以补码形式参与,结果也是补码。
示例:计算 75 (使用8位补码)
- 转换为补码:
+7的补码:0000 0111-5的补码:1111 1011(如上表)
- 执行加法运算:
a = 0b00000111 # +7的补码 b = 0b11111011 # -5 的补码 result = (a + b) & 0xFF # 加法并取低8位,模拟溢出截断 print(bin(result)) # 输出: 0b10 -> 0b00000010 (高位溢出丢弃) - 解读结果:
0000 0010是+2的补码,因此7 - 5 = 2。
示例:计算 -3 4
- 转换为补码:
-3的原码:1000 0011,反码:1111 1100,补码:1111 1101-4的原码:1000 0100,反码:1111 1011,补码:1111 1100
- 执行加法运算:
result = (a + b) & 0xFF print(bin(result)) # 输出: 0b11111001 ``` - 将结果补码
1111 1001转换回十进制:- 符号位为1,是负数。
- 数值位取反:
0000 0110。 - 加1:
0000 0111= 7。 - 因此,原数是
-7。验证:(-3) + (-4) = -7。
5. 扩展知识:移码
移码主要用于浮点数的阶码(指数)表示(如 IEEE 754 标准)。
- 定义:在补码的基础上,将符号位取反。即
移码 = 补码 +2^(n-1)(对于n位数)。 - 目的:使所有指数的机器数都表现为正数,便于浮点数比较大小。
- 示例:8位移码,偏移量
128(2^7)。十进制真值 补码 移码 (补码符号位取反) +5 `
0000 0101|
1000 0101| | -5 |
1111 1011|
0111 1011` |
6. 编程语言中的实践
在高级编程语言(如 Java、C、C++、Python)中,程序员通常直接使用有符号整数类型(如int),编译器或解释器会自动处理补码的转换和运算。
// Java 示例:展示负数的补码表示 public class TwosComplementDemo { public static void main(String[] args) { int positive = 5; int negative = -5; System.out.println("十进制 +5: " + positive); System.out.println("二进制(补码): " + Integer.toBinaryString(positive)); // 输出: 101 (省略前导0) System.out.println("十进制 -5: " + negative); // 输出5 的32位补码表示 System.out.println("二进制(补码): " + Integer.toBinaryString(negative)); // 输出: 11111111111111111111111111111011 } }在 Java 中,Integer.toBinaryString()方法返回的是整数补码表示的二进制的字符串形式(对于负数,是完整的32位补码)。
参考来源
- 原码-反码-补码的详细解释
- 关于二进制的原码 、反码、补码的简要解释说明
- 原码,反码,补码解释
- 原码,反码,补码,移码四种码详细解释
- 计算机原码、反码、补码是什么解释;题目练习
