这次我们直接把这四个数制放到同一张表里对比:原码、反码、补码、移码。它们不是四个孤立的概念,而是同一条二进制规则链上的四个环节。只要理解了“模运算”和“符号位参与运算”这两件事,408 计组里大部分关于补码加减、溢出判断、移码比较大小的题目都能稳定得分。
这篇文章会按“定义 → 转换 → 加减运算 → 溢出判断 → 移码考点 → 经典例题”的顺序展开。先说清楚每个码制的数学本质,再直接进入考法,最后给出全套易错点清单。适合正在复习 408 计算机组成原理、准备期末考,或者面试前快速过一遍数据表示与运算基础的人。
1. 核心考点速览
先给一张总表,把四种码制的关键属性一次性说清。这张表建议直接收藏,做题前先对着它捋一遍思路。
| 码制 | 符号位 | 数值位 | 0 的表示 | 表示范围(n位定点整数) | 与真值的转换方式 | 常考位置 |
|---|---|---|---|---|---|---|
| 原码 | 最高位,0正1负 | 真值绝对值 | +0 和 -0 两种 | -(2^(n-1)-1) ~ +(2^(n-1)-1) | 符号位不变,数值位直接读绝对值 | 概念辨析、溢出边界 |
| 反码 | 最高位,0正1负 | 正数同原码,负数按位取反 | +0 和 -0 两种 | -(2^(n-1)-1) ~ +(2^(n-1)-1) | 负数数值位取反 | 过渡概念,用于推导补码 |
| 补码 | 最高位,0正1负 | 负数反码+1 | 只有一种,全0 | -2^(n-1) ~ +(2^(n-1)-1) | 负数连同符号位取反加1 | 加减运算、溢出判断 |
| 移码 | 与补码符号位相反 | 同补码数值位 | 只有一种 | -2^(n-1) ~ +(2^(n-1)-1) | 补码符号位取反;真值加偏置值 | 浮点阶码、比较大小 |
有几个结论必须刻进脑子:
- 补码比原码、反码多表示一个最负数,例如 8 位补码能表示 -128,而原码、反码只能到 -127。
- 补码的 0 只有一种编码,全是 0;原码和反码都有正零、负零两种编码。
- 移码的 0 也只有一种编码,且移码的最小编码全 0 对应最小的负数。
- 补码加减运算时,符号位参与运算,最终结果自动得到补码形式,不需要额外处理符号位。
- 移码比较大小,直接按无符号数比较即可,这是移码设计的目的之一。
2. 适用学习人群与复习边界
2.1 适合谁看
这套知识点覆盖的人群很宽:
- 408 考研党:计算机组成原理第二章“数据的表示与运算”,几乎每年都会涉及原码、反码、补码、移码中的 1 到 2 题。补码加减和溢出判断是简答题、选择题的高频方向。
- 计算机专业期末考生:不管是“计算机组成原理”还是“数字逻辑”,数制转换和补码运算都是基础题。
- 面试准备者:C/C++ 面试里 int 溢出、unsigned 比较、负数右移等题目,本质就是补码和无符号数的区别。
- 写底层代码的开发者:做嵌入式、通信协议、音视频编解码时,经常要手动处理二进制位、字节序和定点数。
2.2 复习边界
这篇文章解决的是“码制转换 + 补码运算 + 移码比较”这三大块。像浮点数完整规格化、乘除运算器结构、CRC 校验这些内容,本文只会在涉及移码偏置值时提及,不会展开。
换句话说,看完本文你能稳定解决的是:给定一个真值写四种码制、给定补码求真值、补码加减法并判断溢出、移码与补码互转、浮点阶码中移码比较大小。这些都是应试中性价比最高的部分。
3. 前置知识:模运算与机器字长
3.1 模运算的思想
补码的核心是模运算。简单说,一个 n 位二进制计数器,从 0 开始不断加 1,加到全 1 后再加 1,会回到全 0。这个“溢出丢弃”的过程,就是自动取模。
n 位无符号数的模是 2^n。例如 4 位无符号数范围是 0~15,计数器溢出后回到 0,相当于对 16 取模。
补码就是利用这个溢出特性,把减法转换成加法:
x - y = x + y 的补数(对模 2^n 而言)
一个数的补数就是等于 2^n - 这个数。对二进制来说,“取反加一”就是求补数的快捷方式。这就是为什么补码叫“补”码:它补的是模。
3.2 机器字长是什么
机器字长就是一次能处理的二进制位数,常见的是 8、16、32、64。字长决定了:
- 无符号数表示范围:0 ~ 2^n - 1
- 补码表示范围:-2^(n-1) ~ 2^(n-1) - 1
- 原码、反码表示范围:-(2^(n-1)-1) ~ 2^(n-1) - 1
做题时第一件事永远是确认字长。字长不同,同一个二进制串代表的真值完全不同。
4. 四种码制的定义与互相转换
4.1 原码
原码是最直观的表示法:最高位是符号位,剩余位是数值的绝对值。
以 8 位为例:
- +5 的原码是 0000 0101
- -5 的原码是 1000 0101
- +0 的原码是 0000 0000
- -0 的原码是 1000 0000
原码的问题很明显:符号位不能直接参与运算,做加减法需要先判断符号,逻辑复杂,而且有两个 0。
4.2 反码
反码的规定:
- 正数的反码等于原码。
- 负数的反码是符号位不变,数值位按位取反。
所以:
- +5 的反码是 0000 0101
- -5 的反码是 1111 1010
- +0 的反码是 0000 0000
- -0 的反码是 1111 1111
反码本身不常用于直接运算,但在推导补码时是必经路径。
4.3 补码
补码的规定:
- 正数的补码等于原码。
- 负数的补码是反码加 1。
所以:
- +5 的补码是 0000 0101
- -5 的补码是 1111 1011
补码统一了加法和减法,符号位可以直接参与运算。这是计算机中整数默认用补码存储的根本原因。
4.4 移码
移码的定义:
移码 = 真值 + 偏置值
最常见的偏置值是 2^(n-1),也就是把整个取值范围往正方向平移,让最小负数变成全 0。
n 位移码的取值范围正好是 0 ~ 2^n - 1,因此可以直接按无符号数比较大小,这也是移码用于浮点阶码的原因。
8 位二进制,偏置值为 128:
- 真值 +5 的移码 = 5 + 128 = 133 = 1000 0101
- 真值 -5 的移码 = -5 + 128 = 123 = 0111 1011
- 真值 -128 的移码 = -128 + 128 = 0 = 0000 0000
注意,这里使用的偏置值是 2^(n-1)=128。IEEE 754 浮点数的阶码也使用移码,但偏置值改成 2^(k-1)-1=127,k 是阶码位数。这是考试中最容易丢分的地方之一。
4.5 补码与移码的快速互转
当偏置值是 2^(n-1) 时,补码转移码有一个很实用的结论:
移码 = 补码的符号位取反,数值位不变。
验证:
- 真值 +5:补码 0000 0101,符号位取反得到 1000 0101,正好是移码。
- 真值 -5:补码 1111 1011,符号位取反得到 0111 1011,正好是移码。
这个结论可以节省大量计算时间。
但必须注意,这个结论只在偏置值 = 2^(n-1) 时成立。IEEE 754 的偏置值是 2^(k-1)-1,就不能直接符号位取反,需要按真值 + 偏置值重新计算。很多题目在这里设陷阱。
5. 补码加减运算与溢出判断
5.1 补码加减法规则
补码加减法只有两条规则:
- [x + y]补 = [x]补 + [y]补
- [x - y]补 = [x]补 + [-y]补
其中 [-y]补 的求法是:把 [y]补 连同符号位一起取反,再加 1。
例如 8 位补码:
- x = 5,[x]补 = 0000 0101
- y = 3,[y]补 = 0000 0011
- [-y]补 = 1111 1101
- [5 - 3]补 = 0000 0101 + 1111 1101 = 0000 0010(最高位进位丢弃)
结果是 2,正确。
运算时所有位都参与加法,符号位产生的进位直接丢弃,不需要额外处理。
5.2 什么情况会溢出
补码加减法溢出发生在“运算结果超出表示范围”时。以 4 位补码为例,范围是 -8 ~ 7。
两个正数相加,结果超过 7,就是上溢。例如 5 + 4 = 9,9 超过 7,溢出。
两个负数相加,结果小于 -8,就是下溢。例如 -5 + (-4) = -9,-9 小于 -8,溢出。
特别注意:一正一负相加不会溢出,因为结果一定落在两个数的范围内。
5.3 溢出判断的三种方法
第一种:双符号位法,也叫做变形补码。用两个符号位表示正负,00 表示正,11 表示负。加法运算后,如果两个符号位不同,就说明溢出:
- 01 表示上溢,正数相加溢出。
- 10 表示下溢,负数相加溢出。
- 00 或 11 表示没有溢出。
例如 4 位补码加 5 和 4,先用双符号位表示:00101 + 00100 = 01001。两个符号位是 01,上溢。
第二种:单符号位比较进位法。只要最高数值位向符号位的进位,与符号位产生的进位不同,就说明溢出。
第三种:符号位与数值位最高位的进位异或。两个进位不同则溢出。
这三种方法本质一样,考试中推荐使用双符号位法,最直观、不容易错。
5.4 补码加减法完整示例
题目:用 5 位补码计算 7 + 5,并判断是否溢出。
第一步,求补码:
- 7 的补码:00111
- 5 的补码:00101
第二步,相加:
00111 + 00101 ------- 01100第三步,结果 01100,最高位是 0,说明符号位是正,但数值位是 1100,即 12。
检查一下范围:5 位补码范围是 -16 ~ 15,7 + 5 = 12,没有超出范围。
但用双符号位看:
- 7 的双符号位补码:000111
- 5 的双符号位补码:000101
- 相加得到 001100,两个符号位都是 0,没有溢出。
再看 7 + 9:
- 7 的补码:00111
- 9 的补码:01001
- 相加得到 10000
用双符号位:000111 + 001001 = 010000,符号位是 01,上溢。
这里从单符号位角度看,结果是 10000,符号位变成 1,看起来像 -16,但这其实是因为溢出后符号位被覆盖了。所以判断溢出时不能只看最终符号位,必须比较进位。
6. 无符号数与补码的区分
6.1 同一个二进制串,两套解释
无符号数和补码是同一个二进制串的两种解释方式:
- 无符号数:所有位都是数值位,范围 0 ~ 2^n - 1。
- 补码:最高位是符号位,范围 -2^(n-1) ~ 2^(n-1) - 1。
4 位二进制串 1111:
- 按无符号数:15
- 按补码:-1
4 位二进制串 1000:
- 按无符号数:8
- 按补码:-8
这就是“无符号数的补码”这个概念容易混的原因。很多教材里说“无符号数也有补码”,意思是:无符号数本身也可以被解释成补码形式的有符号数,关键看你怎么定义符号位。
6.2 C 语言里的典型陷阱
这段代码是面试常客:
#include <stdio.h> int main() { int x = -1; unsigned int y = 1; if (x < y) { printf("x < y\n"); } else { printf("x >= y\n"); } return 0; }实际输出是 “x >= y”。
原因:C 语言中,有符号数和无符号数做比较时,有符号数会隐式转换成无符号数。-1 的补码是 0xFFFFFFFF,按无符号数解释就是 4294967295,远大于 1,所以 x >= y。
这种按无符号数解释补码的规则,考试中经常结合“无符号数的补码”出选择题。解题时先明确操作数是有符号还是无符号,再决定解释方式。
7. 移码的经典考法
7.1 移码的本质
移码的真正用途是“让比较大小变得简单”。
浮点数比较大小时,如果阶码直接用补码,比较两个负数会非常麻烦,因为补码的数值越大,真值越小。但移码把所有真值映射到无符号数范围,真值越大,移码越大,直接无符号比较即可。
这就是很多 408 题目中浮点数阶码用移码,尾数用原码或补码的原因。
7.2 移码与补码的转换考法
最常见的直接考法是:
题目:设 8 位机器数采用移码表示,偏置值为 128,求十进制真值 -3 的移码。
解法一:-3 + 128 = 125,125 的二进制是 0111 1101。
解法二:-3 的补码是 1111 1101,符号位取反得到 0111 1101。
两种方法结果一致。
再看本题的变体:偏置值为 127,求 -3 的移码。
此时不能直接符号位取反,要按定义计算:-3 + 127 = 124,124 的二进制是 0111 1100。
如果题目问“IEEE 754 单精度浮点数的阶码”,那就是 8 位、偏置 127。这是最容易被惯性思维坑的地方。
7.3 移码加减法的注意事项
移码有两个很隐蔽的性质:
- 移码本身不能直接做加减法。两个移码相加后,结果并不是真实结果的移码,而是多了一个偏置值。例如真值 5 和 3,5 的移码 1000 0101,3 的移码 1000 0011,相加得到 1 0000 1000,符号位进位丢弃后是 0000 1000,即 8。而 5+3=8,8 的移码是 1000 1000。结果差了 128。所以移码加减后必须再减一次偏置值。
- 移码比较大小可以直接按无符号数比较,不需要转换。例如判断 -1 和 -2 的移码,-1 的移码是 127,-2 的移码是 126,所以 -1 > -2,与无符号比较一致。
考试中涉及移码运算时,先问自己:题目让我做的是“比较大小”还是“加减运算”?比较大小用无符号规则,加减运算要修正偏置。
8. 经典例题演练与解析
8.1 例题一:四种码制转换
题目:写出 -13 的 8 位原码、反码、补码、移码(偏置值 128)。
解析:
- 原码:符号位为 1,数值位是 13 的二进制 0001101,所以是 1000 1101。
- 反码:符号位不变,数值位取反,得到 1111 0010。
- 补码:反码加 1,得到 1111 0011。
- 移码:补码符号位取反,得到 0111 0011。
验证移码:-13 + 128 = 115,115 的二进制是 0111 0011,一致。
这道题的易错点在反码。取反时只对数值位取反,符号位保持不变。如果连符号位一起取反,反码就变成了 0111 0010,但这其实是补码符号位取反后的样子,恰好等于移码的数值位,容易混淆。
8.2 例题二:补码求真值
题目:8 位补码 1110 1000 对应的十进制真值是多少?
解析:
方法一:按负数处理。补码减 1 得到反码 1110 0111,再按位取反得到 1001 1000。数值位 0011000 是 24,符号位为 1,所以真值是 -24。
方法二:直接按公式。这是最推荐的做法:原码数值位 = 补码数值位取反加 1。1110 1000 数值位 110 1000 取反得到 001 0111,加 1 得到 001 1000,即 24,符号位为 1,所以是 -24。
还有一种更快的做法:把补码看成“全 1 补码表示 -1”,然后用差值法。1110 1000 与全 1 的 1111 1111 相差 0000 0111,即 7。全 1 表示 -1,所以 1110 1000 表示 -1 - 7 = -8。但这里 1110 1000 实际是 -24,差值与 -1 之间不是这个关系,这种方法不通用。最稳妥的还是取反加一。
8.3 例题三:补码减法与溢出
题目:用 5 位补码计算 -6 - 3,并判断是否溢出。
解析:
- -6 的补码:11010
- -3 的补码:11101
- -6 - 3 = -6 + (-3)
加法:
11010 + 11101 ------- 1101115 位结果保留低 5 位:10111。
10111 是补码,符号位为 1,是负数。数值位取反加 1:01000 + 1 = 01001,即 9,所以真值是 -9。
-6 - 3 = -9,5 位补码范围是 -16 ~ 15,-9 在范围内,不溢出。
用双符号位验证:
- -6 的双符号位补码:111010
- -3 的双符号位补码:111101
- 相加得到 1110111,保留低 6 位,两个符号位都是 11,不溢出。
正确。
8.4 例题四:无符号数陷阱
题目:4 位机器数 1100,按无符号数解释是多少?按补码解释是多少?
解析:
- 无符号数:8 + 4 = 12。
- 补码:符号位为 1,是负数。数值位 100 取反加 1,得到 011 + 1 = 100,即 4,所以真值是 -4。
同一个二进制串,按无符号数是 12,按补码是 -4。这种“解释方式决定值”的题目,是 408 选择题常见的送分题,也是 C 语言隐式转换的考点来源。
9. 常见错误与纠错方法
| 错误现象 | 可能原因 | 纠错方法 |
|---|---|---|
| 负数的原码和补码写反 | 混淆原码与补码的转换步骤 | 记住“负数的补码 = 反码 + 1”,而不是“原码取反加 1” |
| 反码取反时把符号位也取反 | 误以为所有位都取反 | 反码、补码转换时符号位保持不变 |
| 补码 1000 0000 写成不能表示 | 只记住范围,没记住补码的唯一最负数 | 8 位补码可表示 -128,原码、反码不行 |
| 移码直接用补码符号位取反 | 未确认偏置值是否为 2^(n-1) | 先看题目的偏置值,IEEE 754 偏置是 127 |
| 补码加法出现高位进位就直接判溢出 | 混淆“进位”与“溢出” | 溢出判断要看符号位进位与最高位进位是否一致 |
| 无符号数和补码混用 | 忽略解释方式 | 先统一解释成同一类数再比较 |
| 移码加法结果不对 | 忽略偏置值修正 | 两个移码相加后再减一次偏置值;比较大小不用修正 |
| 双符号位写下溢写成 01 | 符号位顺序记反 | 01 表示上溢,10 表示下溢,按高位到低位读 |
10. 复习策略与答题规范
10.1 做题顺序建议
第一次接触这个知识点时,建议按固定流程处理每一道题:
- 看题目标示的字长,确定 n 的数值。
- 判断题目要求的是原码、反码、补码还是移码。
- 如果是补码运算,先写全补码,而不是先写原码再心算。
- 运算时把符号位当作数值位参与加法。
- 算完后用双符号位法或进位比较法检查是否溢出。
- 如果题目涉及浮点阶码,确认偏置值是 2^(n-1) 还是 2^(n-1)-1。
这套流程看起来繁琐,但能避免绝大多数低级错误。
10.2 一个建议:把所有特殊值写一遍
把 8 位的几个特殊值背熟,能大幅提高计算速度:
| 真值 | 原码 | 反码 | 补码 | 移码(偏置128) |
|---|---|---|---|---|
| +127 | 0111 1111 | 0111 1111 | 0111 1111 | 1111 1111 |
| +1 | 0000 0001 | 0000 0001 | 0000 0001 | 1000 0001 |
| +0 | 0000 0000 / 1000 0000 | 0000 0000 / 1111 1111 | 0000 0000 | 1000 0000 |
| -0 | 1000 0000 | 1111 1111 | 0000 0000 | 1000 0000 |
| -1 | 1000 0001 | 1111 1110 | 1111 1111 | 0111 1111 |
| -127 | 1111 1111 | 1000 0000 | 1000 0001 | 0000 0001 |
| -128 | 无法表示 | 无法表示 | 1000 0000 | 0000 0000 |
这张表有三个观察点:
- 补码 -128 是唯一一个原码、反码无法表示的特殊值。
- 移码全 0 是 -128,不是 -0。
- 原码和反码都有两个 0,补码和移码都只有一个 0。
如果做题时发现某个值落在“无法表示”的区间,说明题目可能故意让你判断可表示范围。
11. 结语
原码、反码、补码、移码这一块,难的不是概念本身,而是运算中容易丢分的小细节。考试只要抓住三件事:
第一,补码的最高位是符号位,但符号位要参与运算,溢出靠双符号位判断。
第二,移码是“真值加偏置值”,比较大小直接按无符号数看,做加减法必须修正偏置值。
第三,同一个二进制串在不同解释方式下代表不同的值,无符号数和补码不能混用。
把这三点落实到位,再配合几道完整例题练习,这套考法基本能稳定拿下。建议把这篇文章中的表格截图保存,复习时先看表,再做题,效率会比反复刷网课更高。