原码、反码、补码是计算机中表示有符号整数的三种编码方式,核心目的是解决减法运算转化为加法运算的问题(从而简化CPU设计)。下面从定义、转换、运算、优缺点和应用五个方面清晰讲解:
一、定义与用途
-
原码 (Sign-Magnitude)
- 规则:最高位为符号位(
0
正1
负),其余位表示数值的绝对值。 - 示例:
+5
→0 0000101
(8位表示,下同)-5
→1 0000101
- 问题:
0
有两种表示(+0=00000000
,-0=10000000
),且加减运算复杂(需判断符号)。
- 规则:最高位为符号位(
-
反码 (Ones' Complement)
- 规则:
- 正数:与原码相同。
- 负数:符号位不变,数值位按位取反。
- 示例:
-5
→ 原码1 0000101
→ 反码1 1111010
- 问题:
0
仍有两种表示(+0=00000000
,-0=11111111
),加法需修正。
- 规则:
-
补码 (Two's Complement) ✅ 计算机真实使用的方式
- 规则:
- 正数:与原码相同。
- 负数:反码 + 1(符号位不变,数值位取反后加1)。
- 关键特性:
- 统一
0
的表示:0
只有00000000
。 - 减法变加法:
A - B = A + (-B的补码)
。
- 统一
- 示例:
-5
→ 原码10000101
→ 反码11111010
→ 补码11111011
- 规则:
二、转换方法(以8位为例)
数值 | 原码 | 反码 | 补码 |
---|---|---|---|
+7 | 0 0000111 | 0 0000111 | 0 0000111 |
-7 | 1 0000111 | 1 1111000 | 1 1111001 |
+0 | 0 0000000 | 0 0000000 | 0 0000000 |
-0 | 1 0000000 | 1 1111111 | 无(被 -128 占用) |
-128 | 无原码/反码 | 无 | 1 0000000 |
🔍 补码的特殊值:
- 最小负数:
-128
(8位补码为10000000
,无原码/反码)。- 范围:
-128
到+127
(n
位补码范围:[-2^{n-1}, 2^{n-1}-1]
)。
三、补码的运算(核心!)
1. 加法:直接运算,丢弃进位
-
例1:
5 + 3 = 8
00000101 (+5) + 00000011 (+3) ------------ 00001000 (+8) ✅
-
例2:
7 - 5 = 7 + (-5)
00000111 (+7) + 11111011 (-5的补码) ------------ (1)00000010 → 丢弃进位 → `00000010` (+2) ✅
2. 减法:转化为加其补码
A - B = A + (-B的补码)
- 例:
-3 - 2 = (-3) + (-2)
-3的补码 = 11111101 -2的补码 = 11111110 11111101 + 11111110 ------------ (1)11111011 → 丢弃进位 → `11111011`(即 -5 的补码)✅
3. 溢出判断
- 规则:若两个正数相加得负数或两个负数相加得正数,则溢出(结果错误)。
- 硬件实现:检查最高位的进位
C_n
和次高位的进位C_{n-1}
:- 溢出标志:
V = C_n ⊕ C_{n-1}
(异或:不同为1)。
- 溢出标志:
四、为什么计算机用补码?
- 统一加减法:CPU只需设计加法器即可完成加减法。
- 消除
0
的歧义:0
唯一表示为00...0
。 - 扩大表示范围:可表示最小负数(如8位补码的
-128
)。 - 简化运算逻辑:无需额外电路处理符号位。
五、快速计算技巧(应试)
-
求负数补码:
- 从右向左,保留第一个
1
之前的位不变,之后取反。 - 例:求
-20
的补码(8位):20原码:00010100 保留最右侧的1及其右边的0:→ _ _ _ 1 0 0 左侧按位取反:1110 → 11101100 ✅
- 从右向左,保留第一个
-
补码转十进制:
- 若符号位为
1
,先减1
再按位取反,加负号。 - 例:
11100011
→ 减1:11100010
→ 取反:10011101
=-29
✅
- 若符号位为
六、考研典型题型(需掌握)
- 计算给定数值的原码、反码、补码(含负数)。
- 补码加减运算及溢出判断(结合状态寄存器)。
- 结合IEEE 754浮点数(符号位独立处理)。
- 设计ALU运算电路(如加法器、溢出标志生成逻辑)。
建议动手计算下面几组值:
① -12
的原、反、补码 → ② 18 + (-15)
的补码加法 → ③ -100
在16位补码下的表示。
补充:仅做了解即可,在很多小伙伴学习补码的时候会好奇,为什么这样就可以把减法转换成加法,在这里我们仅做简单介绍,因为后面确实涉及到一些数论的知识,也没有必要从头介绍。
我们知道计算机世界中整数的有范围的(如8位数范围是0~255或-128~127),它遵循的是“模运算”,模运算的定义是:
在一个模 M 系统中,一个数 A 等价于 A + K×M(K 为任意整数)
在生活中我们还有接触更多的模运算,比如钟表:15点 ≡ 3点 mod 12(因为 15 - 12 = 3)。
重要的是负数可以等价表示,在模 M 系统中,负数 -A 可表示为:
-A ≡ M - A mod M
(模 256 的8位系统):
-5 ≡ 256 - 5 = 251 mod 256
因此 7 - 5 = 2 等价于 7 + 251 = 258 ≡ 258 - 256 = 2 mod 256
(计算机中 251 正是 -5 的补码形式:11111011)
补码中的负数 -A 本质上是它在模 2^n 系统中的正数等价表示(即 2^n - |A|)!
所以补码的根本设计是:负数 = 模 - 绝对值
那又有同学可能要问了,为什么是取反加一就获得补码了呢?
这取反加一的过程其实就是做了上面那个公式:负数 = 模 - 绝对值,这个摸得值是很好确定的,就是它的上限2^n,后面的绝对值用原码即可,但由于2^n是要溢出的,所以为了适应计算机硬件,我们用(2^n-1)-|A|+1,这个式子的2^n-1)-|A|这部分是做取反,后面那个加一就是取反再加一中的加一,可能又有小伙伴要问了,前面那部分真的那么巧吗,就是二进制取反,还真的那么巧妙,二进制运算的逻辑中确实暗含了这一条规律,不信的小伙伴们可以自己找几个例子尝试一下,去更深刻的体会一下那巧妙的运算过程,或许你会明白它为什么是这样,至此我们找到了补码为什么这样可以获得补码的原因,那计算机又是怎么把减法变成加法的呢,到这里其实已经很简单了,很普通的带入转换
A - B = A + (2^n - B) ≡ A - B mod 2^n(丢弃进位即模运算)。
那么为什么要如此费劲的研究补码呢?为什么还需要把减法转换成加法呢?是不是还有什么数学原因啊,其实没有,这样做的原因就是为了节省成本,计算机中加法器的成本是低于减法器的,前面那些如此专业,但它的原因却又如此朴实无华,不禁叫人莞尔一笑。