补码和移码,是计算机组成原理考研里“感觉听懂了、一上手就错”的知识点。很多同学复习到数据表示与运算这一章,原码反码都能写,一到补码加减法、移码阶码就开始含糊,做题全靠猜。这篇文章直接按考研考法来拆解,把真值到原码、反码、补码、移码的转换,补码加减与溢出判断,移码在浮点数阶码里的应用,符号扩展与截断,以及最容易踩的坑全部过一遍。
文章覆盖四个重点:一是四种机器数的定义与转换流程,二是补码加减运算和双符号位溢出判断,三是移码作阶码的常见出题方式,四是应试记忆方法和配套练习顺序。全程用具体例子说话,不玩概念,每个点都按“考法 + 解法 + 常见错误”的节奏展开。如果你正在准备 408 统考或自主命题的计组科目,建议直接收藏。
1. 为什么补码和移码是计组必考重点
1.1 从考频看
计算机组成原理的数据表示与运算章节,几乎是每年必考。408 统考中,选择题经常围绕原码、反码、补码、移码的转换,补码加减法溢出判断,以及 IEEE 754 浮点数表示来出题。有时候一个选择题里同时考了三种机器数的转换,甚至把无符号数、有符号数和浮点阶码放在一起查。自主命题院校中也常有这类基础计算题。
补码和移码之所以高频,是因为它们直接关系到后面的运算器、ALU、浮点数加减法。机器数转换会了,补码加减会了,后面讲加法器进位链、补码一位乘法、Booth 算法、浮点加减实现时,你才能跟上硬件逻辑。否则翻到后面章节,很多问题仍然卡在“这个数到底在计算机里长什么样”。
1.2 从考核方式看
这类题目的特征非常明显:给一个十进制真值,让你写出 8 位补码或移码;或者反过来,给一个补码,让你求它对应的真值;再进阶一点,给两个补码做加减,判断结果是否溢出。这些题没有太多需要背的宏大理论,核心是算得准、算得快。
从得分性价比来看,这部分比流水线、Cache 计算题更划算。流水线和 Cache 往往题型灵活,一个条件变了结果全变;而补码和移码只要掌握固定流程,错误率就能压得很低。换句话说,这是计组里少有的“靠熟练能拿满分”的基础考点。
2. 机器数基本概念:真值、原码、反码、补码、移码
2.1 五组定义
先明确一件事:真值就是我们日常写的有符号十进制数或二进制数,比如 +13、-1101。机器数则是真值在计算机内部的二进制编码形式。真值不能直接被计算机存储,机器数才是硬件看的。
| 机器数 | 定义 | 例子(8位,真值 -13) |
|---|---|---|
| 原码 | 最高位为符号位,0 表示正,1 表示负,数值位为绝对值的二进制 | 10001101 |
| 反码 | 正数同原码;负数在原码基础上符号位不变,数值位按位取反 | 11110010 |
| 补码 | 正数同原码;负数在反码基础上末位加 1 | 11110011 |
| 移码 | 补码符号位取反;或直接按真值加偏置量 2^(n-1) | 01110011 |
注意,负数补码更常见的推导路径是“原码 -> 数值位取反再加 1”。这里容易出问题的点是:对负数求补码时,符号位不参与取反和加 1,只在最后原样保留。另外,很多同学会问“补码能表示 -128,那 -128 的原码是多少”?这是个陷阱。8 位的 -128 没有 8 位原码和反码,因为原码反码表示不了它,它只在补码中靠 10000000 来对应。
2.2 数值范围对比
考研最常出的坑题之一,就是让你比较几种机器数的表示范围。以 8 位为例:
| 机器数 | 表示范围 |
|---|---|
| 原码 | -127 到 +127,即 -(2^7 - 1) 到 +(2^7 - 1) |
| 反码 | -127 到 +127,同样 -(2^7 - 1) 到 +(2^7 - 1) |
| 补码 | -128 到 +127,即 -2^7 到 +(2^7 - 1) |
| 移码 | 真值范围 -128 到 +127,编码范围为 00000000 到 11111111 |
核心区别在补码:它比原码、反码多表示一个最小数。原因是补码状态下 0 只有唯一编码 00000000,原来用于表示“-0”的那个编码,在补码中被腾出来表示 -128。具体到 8 位二进制,10000000 不是 -0,而是 -128。很多同学在这里丢分。
2.3 用“模”理解补码
补码的本质可以理解为模运算。对 n 位补码,负数的补码等于 2^n - |真值|。以 8 位为例,-13 的补码是 256 - 13 = 243,243 写成 8 位二进制正是 11110011。这个理解方式有两个好处:
第一,补码加减法自然满足模运算规则,溢出就是结果超出模 2^n 可表示范围。第二,0 只有一种表示,因为 256 - 0 也是 0。理解了模,后面做溢出判断会顺手很多。
3. 四种机器数互相转换,必须形成肌肉记忆
3.1 从真值求四种机器数
建议按“真值 -> 原码 -> 反码 -> 补码 -> 移码”的路径走,不用每次都回到真值重新算。
以 -59 为例,先求它的 8 位二进制绝对值:59 = 00111011。然后:
| 步骤 | 运算 | 结果 |
|---|---|---|
| 符号位 | 负数,符号位为 1 | 1 |
| 原码 | 符号位 + 绝对值数值位 | 10111011 |
| 反码 | 符号位不变,数值位按位取反 | 11000100 |
| 补码 | 反码末位加 1 | 11000101 |
| 移码 | 补码符号位取反 | 01000101 |
上面这个例子完整走完,基本就把四种机器数的关系串起来了。正数的处理更简单:正数的原码、反码、补码完全一样,移码等于符号位从 0 换成 1。例如 +59 的八位补码是 00111011,移码就是 10111011。
3.2 从补码求真值
这是一个反向过程。两种方法都可以:
方法一:按位权展开。补码最高位代表 -2^(n-1),其余位正常展开。对 8 位补码 11110011:
11110011 = -128 + 64 + 32 + 16 + 2 + 1 = -128 + 115 = -13方法二:先看符号位。如果符号位为 1,则对补码整体取反加 1,得到该负数绝对值,再补上负号。11110011 整体取反得 00001100,加 1 得 00001101,即 13,所以原来表示的是 -13。
考试中方法二更实用。注意完整补码求原码时,如果是负数补码,从最右侧开始找到第一个 1,这个 1 左边的各位取反,符号位保持不变,也能快速得到原码。
3.3 补码和移码互转
补码和移码之间的转换是一个很省时间的技巧:把补码最高位取反,就是移码;反之亦然。这个性质在算“某个小数的移码是多少”时非常好用。
不过有一点要提醒:移码的最高位并不是严格的符号位。移码 00000000 表示的是最小真值 -128,移码 10000000 表示的是真值 0。所以在直接读移码时,不要按补码的符号位习惯去理解。
4. 补码加减运算与溢出判断
4.1 补码加减规则
补码最大的优点就是减法可以转化成加法,加减法在硬件上统一用加法器实现。
[X + Y]补 = [X]补 + [Y]补 [X - Y]补 = [X]补 + [-Y]补关键是 [-Y]补 怎么求。正确做法是对 [Y]补 按位取反再加 1,符号位也参与取反和加 1。比如 Y = -3,[Y]补 = 11111101,逐位取反得 00000010,加 1 得 00000011,这个 00000011 正好是 +3 的补码,也就是 [-Y]补。
对应真题里常给的填空是“已知补码求负数的补码”,其实就是这个操作。最容易错的地方是:只对数值位取反,没有对符号位取反,或者加 1 只加在数值位末尾却忘了进位会影响符号位。所以一定要记住,[-Y]补 是对整个 [Y]补(包括符号位)取反加 1。
完整计算示例,求 5 - (-3):
[5]补 = 00000101 [-3]补 = 11111101 [3]补 = 00000011 5 - (-3) = [5]补 + [3]补 = 00000101 + 00000011 = 00001000 = +8这个例子直观说明补码能把减负号变成加正数,而且结果完全正确。
4.2 溢出判断的两种方法
8 位补码表示范围是 -128 到 +127,两个正数相加结果超过 127,或者两个负数相加结果小于 -128,就发生溢出。但考试时不能只靠“感觉值太大”判断,必须用硬件可实现的规则。
方法一:单符号位法。补码相加时,如果最高数值位产生的进位 C1 和符号位产生的进位 C 不相同,则发生溢出。只看符号位进位或只看最高数值位进位都会判断错。
方法二:双符号位法,也叫变形补码法。运算前,把 8 位补码扩展成两位符号位,正数为 00,负数为 11,然后一起做加法。运算结果若两位符号位不同,说明溢出;相同则未溢出,而最高符号位才是真正的符号。
举例,8 位补码计算 120 + 10,正确结果应该是 130,超出 8 位补码范围。
[120]补 = 01111000 [10]补 = 00001010 01111000 + 00001010 = 10000010运算结果的符号位从 0 变成 1,出现了正数加正数得到负数的情况,说明溢出。再看进位:最高数值位的进位 C1 = 1,符号位的进位 C = 0,两种情况不同,所以按单符号位法也能判断出溢出。
再举一个负数相加溢出的例子,计算 -60 + (-70),正确结果应该是 -130:
[-60]补 = 11000100 [-70]补 = 10111010 11000100 + 10111010 = 01111110两个负数相加得到了正数 01111110,很明显溢出。此时最高数值位的进位 C1 = 0,符号位的进位 C = 1,同样因为 C 和 C1 不同而判定溢出。
4.3 无符号数的补码视角
补码运算电路和无符号数运算电路本质是同一套二进制加法器。区别只在于解释结果的方式:无符号数范围是 0 到 2^n - 1,两个无符号数相加若最高位产生进位,说明结果超出 n 位能表示的范围,这是“进位”;两个无符号数相减,若最高位产生借位,则说明不够减。
这一点在真题中偶尔会以“无符号数比较大小”或者“补码与无符号数混合比较”的形式出现。做题时注意区分:比较两个无符号数,直接按位比较即可;比较两个有符号补码,在符号位不同时,符号位为 0 的数一定大于符号位为 1 的数,符号位相同时再比较数值位。
5. 移码的经典考法:浮点阶码与大小比较
5.1 移码为什么能方便比较大小
补码虽然计算方便,但直接比较大小并不直观。比如 8 位补码中,+1 是 00000001,-1 是 11111111,如果按无符号数比较,11111111 反而大于 00000001,单看补码无法判断实际大小。
移码的思路是给所有真值统一加一个偏置量。对 n 位移码,通常偏置为 2^(n-1),所以:
[x]移 = x + 2^(n-1)8 位情况下,真值 -128 的移码是 0,真值 0 的移码是 128,真值 +127 的移码是 255。这样所有移码在二进制上看就是一个无符号数,谁大谁小直接按位比大小就行,不需要关心正负号。这正是浮点数阶码选用移码的核心原因。
5.2 浮点数阶码中的移码
IEee 754 单精度浮点数的阶码字段是 8 位,双精度阶码字段是 11 位。题目如果直接给出“阶码用移码表示,偏置量为 128”,那就按常规移码计算。但如果题目明确说是 IEEE 754 单精度格式,那么阶码偏置是 127,不是 128。
举例:单精度浮点数中,阶码字段 10000001 对应的真值阶码是多少?10000001 作为无符号数是 129,减去偏置 127,得到真值阶码 +2。反过来,若真值阶码为 -126,则阶码字段等于 -126 + 127 = 1,也就是 00000001。注意这里的加 1 不是补码加 1,而是偏置计算中的加法,不要混在一起。
考场上如果题目不说明偏置,通常默认偏置就是 2^(n-1)。但遇到 IEEE 754 字眼时,一定要先确认题目给出的偏置是多少。很多真题故意在这一点上设置区分度。
5.3 移码和补码的换算题
移码与补码的换算题也很常见。规则是补码符号位取反得到移码。例如,8 位补码 11110011 表示 -13,符号位取反后得到 01110011,这就是同样的真值 -13 的 8 位移码。
如果题目给的是“偏置为 128 的移码”,要转回真值,可以直接按无符号数读出来再减 128。比如 01110011 的无符号值是 115,115 - 128 = -13。这个思路比强记二进制更快。
6. 补码的符号扩展与截断
6.1 符号扩展
把短位数的补码扩展成长位数的补码时,规则很简单:正数在最高位补 0,负数在最高位补 1。比如 8 位补码 00000101(+5)扩展到 16 位是 0000000000000101;8 位补码 11110011(-13)扩展到 16 位是 1111111111110011。
这里要注意一点:对负数补码做符号扩展,并不是在数值位前面补 0,而是补符号位。原码扩展也类似,正数补 0,负数符号位保持不变,数值位前面补 0。例如 8 位原码 10001101(-13)扩展到 16 位,应写为 1000000000001101,而不是 1000000010001101。
真题中经常用符号扩展考“两个不同位数的补码相加”,先统一位数,再相加,最后判断结果。这类题的陷阱往往是漏掉符号扩展,直接把低位补码当作高位补码使用。
6.2 截断
截断是把长位数变成短位数,保留低位,丢掉高位。问题在于,截断有可能改变符号位,导致数值解释完全错误。
举个例子,16 位补码 0000000011000000,按无符号值算是 192,但截断成 8 位后得到 11000000,如果把它当 8 位补码解释,结果是 -64,和原值相差很大。因此截断不能随便用,只有确定截断后结果仍在目标位数表示范围内时,才能保持数值不变。
考试中如果在判断题或选择题里看到“把一个 16 位补码直接截断成 8 位后结果不变”,要立刻警惕。正确说法应该是:只有当原值处于 8 位补码可表示范围 -128 到 +127 内,且截断后符号位没有变化时,结果才可能一致。
7. 高频易错点清单
| 易错点 | 常见错误做法 | 正确理解 |
|---|---|---|
| 负数求反码 | 对整体按位取反 | 符号位不变,只对数值位取反 |
| 负数求补码 | 反码末位加 1 时把符号位也加进位 | 符号位不参与补 1 的直接计算,但进位可能影响数值位 |
| 求 [-Y]补 | 只对数值位取反加 1 | 对整个补码包括符号位取反加 1 |
| 8 位补码 10000000 | 认为表示 -0 | 表示 -128 |
| 0 的表示 | 认为原码、反码、补码的 0 都唯一 | 原码和反码有 +0 和 -0,补码 0 唯一 |
| 溢出判断 | 只看符号位进位 | 需要比较符号位进位和最高数值位进位是否相同 |
| 移码偏置 | 一律写成 128 | IEEE 754 单精度阶码偏置为 127,要按题目判断 |
| 移码读法 | 把移码最高位当符号位 | 移码是无符号数视角,直接比较大小 |
| 符号扩展 | 负数补码在数值位前补 0 | 负数补码符号扩展补 1 |
| 截断结果 | 以为截断一定保留原值 | 截断后可能改变符号位解释,只有在小范围内才安全 |
8. 短期记忆方法与考场做题策略
8.1 记忆口诀
这一节给出几个适合背下来的口诀,覆盖大多数基础转换。
第一个是“正数三码相同,负数原到反要取反,反到补要加一”。也就是说正数的原码、反码、补码完全一样,负数的反码在原码基础上符号位不变、数值位取反,补码在反码基础上末位加 1。
第二个是“补码再求补,连同符号一起取反加一”。这用来求相反数的补码,比如已知某数补码,求它的相反数补码。注意“连同符号”四个字,是防止失误的关键。
第三个是“补码取反最高位,就是移码”。补码和移码的转换本质上就是最高位翻转。
第四个是“溢出看 Cn 和 C1,不同就溢出”。C 表示符号位产生的进位,C1 表示最高数值位产生的进位,两者不一致时结果超出表示范围。
8.2 解题流程
拿到一道机器数题目,按固定顺序做,能减少漏算和错算。
| 阶段 | 操作 |
|---|---|
| 第一步 | 读题,确认 n 位数,确认有无符号,确认偏置量 |
| 第二步 | 把十进制真值转成二进制绝对值 |
| 第三步 | 按原码、反码、补码、移码顺序依次转换 |
| 第四步 | 做补码加减时,先求 [-Y]补,再统一相加 |
| 第五步 | 记录符号位进位和最高数值位进位,判断溢出 |
| 第六步 | 如果是浮点数题目,单独处理阶码偏置 |
| 第七步 | 检查 0 的表示和表示范围边界 |
这套流程几乎适用于所有基础选择题。做完之后再用“是否超出 n 位补码范围”快速复核一次结果是否合理。
9. 配合 408 真题和王道复习怎么安排
补码和移码不需要太长周期,适合集中突破。第一轮复习时,先看教材或王道对应章节里关于数据表示和运算器的部分,把例题自己动手算一遍,不看答案直接写过程。这一章不建议只听课,因为听课容易产生“我懂了”的错觉,实际一写就错。
第二步是刷真题。408 统考历年真题里涉及数据表示的选择题都可以做,不用全做完,按年份拉一遍就能发现高频题型。做错的题目重点看是转换错了、加减错了,还是溢出判断错了,分类整理成自己的错题手册。
第三步是针对性强化。如果错误集中在补码加减法,就找几道同类计算题反复练;如果错误集中在浮点数阶码,就专门练 IEEE 754 的阶码字段转换。王道复习体系里的章节练习和真题对应练习题足够覆盖这些点,按正常渠道使用即可,不需要额外找来路不明的资料。
最后说一句硬道理:这部分题目不需要创造力和超凡理解,核心是熟练。只要能把真值到四种机器数的链路练成条件反射,把补码加减和溢出判断练成固定套路,考场上基本不会丢分。建议趁热把 408 历年真题里所有涉及原码反码补码移码的题过一遍,再对照本文的易错点清单逐条核对自己有没有中招。