原码、反码、补码、移码
约 1057 字大约 4 分钟
2026-10-04
机器里只有 0 和 1,负号存不进去,怎么办?——拿最高位当符号位:0 正 1 负。 四种码制就是四种「安排符号位」的方案:原码最像人话,反码是跳板,补码是主角,移码为比大小而生。
一、原码:最像「人话」的码
规则:符号位 + 绝对值,负数只要把符号位改成 1。
+45→00101101−45→10101101
一眼就懂,但有两个痛点:
- 零有两个:+0=00000000,−0=10000000,浪费一个编码
- 减法很麻烦:5−3 和 3−5 对符号的处理逻辑完全不同,硬件得单独造个减法器
二、反码:负数按位取反(过渡方案)
规则:正数不变;负数 = 符号位不动,数值位按位取反。
−45:原码10101101→反码11010010
反码仍然有 +0 和 −0(11111111),它真正的价值是——求补码的跳板。
三、补码:让减法消失的「模」思想
先看一个时钟
12 小时制的钟,现在 10 点,想调到 1 点:
- 往回拨 9 格:10−9=1 ✅
- 往前拨 3 格:10+3=13≡1(mod12) ✅
减 9 = 加 3,因为 9+3=12(模)。只要加出来的数超过模,扔掉进位,结果就对。
8 位机器的「模」是 28=256
−3≡253(mod256)253=111111012
所以 11111101 就是 −3 的补码——减法变成了加法,减法器下岗:
5−3=00000101+11111101=100000010丢进位00000010=2✅
怎么求补码?
| 真值 | 求法 |
|---|---|
| 正数 | 和原码一样,不变 |
| 负数 | 反码 +1;或速算法:从右往左找到第一个 1,它和右边不动,左边全部取反 |
−3: 10000011取反11111100+111111101
补码的两大收益
- 零唯一:00000000 只表示 +0,省出来的 10000000 分给 −128 → 范围多一个
- 减法变加法:a−b=a+[−b]补,CPU 一个加法器走天下
四、移码:为「比大小」而生
规则:补码的符号位取反(等价于真值 +2n−1)。
| 真值 | 补码 | 移码 |
|---|---|---|
| −128 | 10000000 | 00000000 |
| 0 | 00000000 | 10000000 |
| +127 | 01111111 | 11111111 |
妙处:移码当成无符号数看,数值大小顺序和真值完全一致(−128 最小 → 0000 0000 最小)。比较器不用管符号位,直接比。
为什么浮点数的阶码用移码?
对阶、比较阶码大小时,移码可以当普通无符号数直接比大小,硬件简单。 呼应上一章:阶码(移码)定范围,尾数(补码/原码)定精度。
五、8 位典型值对照总表
| 真值 | 原码 | 反码 | 补码 | 移码 |
|---|---|---|---|---|
| +127 | 0111 1111 | 0111 1111 | 0111 1111 | 1111 1111 |
| +1 | 0000 0001 | 0000 0001 | 0000 0001 | 1000 0001 |
| +0 | 0000 0000 | 0000 0000 | 0000 0000 | 1000 0000 |
| −0 | 1000 0000 | 1111 1111 | —(就是 +0) | — |
| −1 | 1000 0001 | 1111 1110 | 1111 1111 | 0111 1111 |
| −127 | 1111 1111 | 1000 0000 | 1000 0001 | 0000 0001 |
| −128 | 无法表示 | 无法表示 | 1000 0000 | 0000 0000 |
六、范围速查
n 位机器字长(含 1 位符号位):
| 码制 | 定点整数 | 定点小数 |
|---|---|---|
| 原码 / 反码 | −(2n−1−1)∼+(2n−1−1) | −(1−2−(n−1))∼+(1−2−(n−1)) |
| 补码 / 移码 | −2n−1∼+(2n−1−1) | −1∼+(1−2−(n−1)) |
速记口诀
- 正数三码合一:原码 = 反码 = 补码
- 负数:反码 = 原码数值位取反;补码 = 反码 +1;移码 = 补码符号位取反
- 补码 / 移码比原码 / 反码多表示一个 −2n−1(零唯一省出来的格子)
七、转换演练
演练 1:+45 的四种码
45=32+8+4+1=1011012
- 原码 = 反码 = 补码 = 00101101(正数三码合一)
- 移码 = 符号位取反 = 10101101
演练 2:−52 的四种码
52=32+16+4=1101002
- 原码:10110100=10110100
- 反码:数值位取反 →11001011
- 补码:反码 +1→11001100
- 移码:补码符号位取反 →01001100
演练 3:补码 → 真值(逆向)
已知 8 位补码 11100110,求真值:
- 符号位 1 → 负数
- 速算法反向用:11100110 右起第一个 1 在第 0 位,左边全取反 →10011010
- 100110102=26 → 真值 −26
验算:−26 原码 10011010 → 反码 11100101 → 补码 11100110 ✅