计算机组成原理第 2 章:数据的表示和运算
408 计算机组成原理「数据的表示和运算」复习:核心知识点、真题题型、通用解法与易错点。
Last updated on
本章依据本站的 408 真题和 408 模拟选择题整理。站内的真题将本章划为 5 大部分:数制与编码、整数表示和运算、浮点数表示和运算、C 语言类型转换、运算方法和运算电路;模拟题又重点补充了移位、补码加减器、Booth 乘法、浮点精度等细节。(Any Docs)
从站内收录的真题分布来看,本章真正需要重点攻克的是:
| 层级 | 题型 | 重要性 |
|---|---|---|
| S | IEEE 754 浮点数 | ★★★★★ |
| S | 补码、溢出、移位 | ★★★★★ |
| S | C 语言整数/浮点类型转换 | ★★★★★ |
| A | CF、OF、SF、ZF 与加减器 | ★★★★☆ |
| A | 浮点加减、舍入、精度 | ★★★★☆ |
| A | 乘除法及硬件实现 | ★★★★☆ |
| B | 海明码、数制编码 | ★★★☆☆ |
尤其值得注意的是,2011、2017、2020 年都出现了能够串起多块知识的综合题,因此第 2 章绝不是“背几个补码公式”就行,而是要真正建立 机器位模式 → 数值解释 → 运算 → 标志位 → C 类型这一整套思维。(Any Docs)
一、本章最核心的统一思想
先记住一句话:
计算机里存的永远只是 0/1 位串;所谓 int、unsigned、float,只是对同一串比特采用不同解释规则。
例如 8 位机器数
如果按 unsigned 解释:
如果按 8 位补码解释:
这就是第 2 章几乎所有综合题的根。
所以遇到题目时,建议固定采用:
二、题型 1:补码机器数与真值互求
这是本章所有整数题的基础。
1. 无符号数
一个 位无符号整数范围:
例如:
2. 位补码范围
必须死记:
所以:
这就是为什么补码存在一个著名的不对称:
也因此会产生一个后面极重要的特殊溢出:
3. 已知补码求真值
正数最高位为 0,直接按无符号数算。
负数最高位为 1,最快公式是:
设机器数按无符号解释为 ,则
例如:
8 位补码:
所以:
这种方法比每次“取反加 1”还快。
三、代表真题:2010 年补码乘法溢出
站内的 2010 真题给出四个 8 位补码:
问若乘积仍放入 8 位寄存器,哪种乘法会溢出。(Any Docs)
先全部翻译:
8 位补码要求:
于是检查数学乘积:
远超 127,因此溢出。
这类题的通法
千万不要直接二进制硬乘。
直接:
对于选择题,这是最快方法。
四、题型 2:给定 0/1 数量,求补码最大值或最小值
2015 真题
题意:一个 8 位补码由 3 个 1 和 5 个 0 组成,问它能表示的最小整数。(Any Docs)
补码各位真正的权值是:
要最小:
第一位一定放 1:
还剩两个 1。
注意这里极容易反着想。
现已得到:
剩下两个正权值会让数字“变大”。
所以应当让增加量尽可能小,即放最低位:
真值:
因此答案:
一般规律
如果题目问补码“最负”,千万不要简单地“把 1 往高位摆”。
补码符号位权值特殊:
而其他位均是正权。
五、题型 3:算术移位与逻辑移位
这是极高频基础题。
1. 逻辑右移
不管原数正负:
例如:
逻辑右移:
2. 算术右移
用于带符号补码数:
所以:
算术右移:
这正是站内 2018 真题考查的内容。(Any Docs)
六、算术左移什么时候溢出?
模拟题里有一道非常值得掌握:
一个 4 位补码 算术左移一位,什么时候发生溢出?(Any Docs)
左移:
原符号位:
新符号位:
因此:
因为算术左移相当于乘 2。
例如:
左移:
如果还按 4 位补码解释:
显然:
发生溢出。
所以以后见到:
左移一位是否溢出
优先检查:
七、一个非常容易混的细节:右移与除以 2
补码算术右移确实通常对应除以 2,但负奇数要特别注意舍入方向。
例如:
算术右移:
所以硬件算术右移得到:
而现代 C 的整数除法:
因为 C 整数除法向 0 截断。
因此:
“算术右移就是带符号整数除以 2”
对偶数没问题,对负奇数不能无脑等同。
八、题型 4:补码加减法与溢出 OF
这是 408 最爱考的地方之一。
对于 位补码:
加法器根本不知道它们“有符号还是无符号”。
硬件只负责:
然后 CPU 根据标志位做不同解释。
九、带符号加法 OF 判断
最简单的中文口诀:
同号相加,结果异号,则溢出。
例如 8 位:
两个正数:
结果机器数却会变成负数。
溢出。
形式化:
设操作数符号位为 ,结果符号位 :
十、带符号减法 OF 判断
对于:
口诀:
异号相减,结果符号和被减数不同,则溢出。
公式:
十一、代表真题:2014 年溢出
真题给:
用 8 位补码计算几个表达式,问哪个溢出。(Any Docs)
范围:
检查:
正常。
注意:
正常。
而:
超出:
所以溢出。
这个题专门利用:
干扰判断。
十二、CF 和 OF 到底有什么区别?
这是第二章最重要区别之一。
OF
回答:
如果把这一位串解释为“有符号补码”,数学结果是否越界?
CF
回答:
如果把这一位串解释为“无符号数”,加减运算有没有进位/借位?
因此:
同一条 ALU 运算可以:
也完全可以:
它们没有必然关系。
十三、2023 真题:OF 和 CF 一起考
真题给:
执行:
问 OF 和 CF。(Any Docs)
先算 signed:
不溢出:
再单独按 unsigned 看。
的 32 位补码如果解释成 unsigned:
显然:
执行无符号减法需要借位:
所以:
以后这种题必须分两条线
不要企图一次算完:
十四、CF 有一个必须注意的坑
不同 CPU/教材对“减法 CF”定义可能不同。
有的体系:
表示产生借位。
而有的体系结构通过加法器最高进位定义 carry,减法时语义可能反过来。
所以考研遇到 CF,一定看题目怎样规定。
本站里的相关真题明确按照“进位/借位标志”的语义处理。(Any Docs)
十五、题型 5:同一个加法器为什么能做四种运算?
2011 年大题直接问过:
带符号加、带符号减、无符号加、无符号减能否共用一个加法器?(Any Docs)
答案:
原因:
无论 signed 还是 unsigned,低 位的二进制运算规则完全一样。
减法:
转成:
因此可以使用:
实现所有整数加减。
差别只在于:
这就是“机器级位运算”和“高级语言数值意义”的典型分离。
十六、减法器输入怎么接?
本站模拟题里有一道很典型:
已知 ,要求用 8 位加减器算 ,问两个数据输入和最低位进位分别是什么。(Any Docs)
因为:
所以加法器输入:
第一路:
第二路:
最低位进位:
即:
这是典型硬件题。
十七、ZF、SF 怎么判断?
这两个反而最简单。
ZF
结果是不是全 0:
SF
结果的最高位:
但:
SF 只是机器结果的符号位,不代表数学结果一定正确。
发生 OF 时:
甚至可能恰好是错误符号。
十八、题型 6:海明码
站内 2013 真题:
8 位数据使用海明码,并要求能够纠正 1 位错误,至少需要几个校验位?(Any Docs)
若数据位:
校验位:
单错纠正要求:
为什么?
总共有:
个可能出错的位置。
加上:
种“无错误”。
需要编码至少:
种状态。
本题:
试:
有:
不行。
试:
有:
所以:
十九、海明码进一步怎么出题?
408 还可能把题目升级成:
给出若干数据位,要求:
- 确定校验位数;
- 校验位放在哪里;
- 计算各校验位;
- 找错误位置;
- 判断能否检测双错。
校验位通常放在:
位置。
因此:
记住:
位置编号的二进制哪一位为 1,就归对应校验位管理。
这是海明码真正的核心。
二十、题型 7:IEEE 754——本章第一大题型
这部分必须熟到看到十六进制能直接拆字段。
单精度 float
共 32 位:
| 字段 | 位数 |
|---|---|
| 符号 | 1 |
| 阶码 | 8 |
| 尾数 | 23 |
规格化数:
单精度偏置:
实际指数:
有效精度不是 23 位,而是:
因为最高位:
是隐藏位。
二十一、双精度 double
| 字段 | 位数 |
|---|---|
| 符号 | 1 |
| 阶码 | 11 |
| 尾数 | 52 |
偏置:
有效精度:
二十二、IEEE 754 四种特殊情况
这个表建议直接背。
| 阶码 | 尾数 | 含义 |
|---|---|---|
| 全 0 | 全 0 | |
| 全 0 | 非 0 | 非规格化数 |
| 非全 0/1 | 任意 | 规格化数 |
| 全 1 | 全 0 | |
| 全 1 | 非 0 | NaN |
二十三、IEEE 真题第一类:十进制 → float
2011 真题
题目给:
要求 IEEE 754 单精度机器数。(Any Docs)
第一步:
规格化:
符号:
实际指数:
阶码:
二进制:
尾数:
所以:
整理为十六进制:
固定模板
看到:
十进制 → IEEE 754
永远:
二十四、IEEE 真题第二类:机器码 → 真值
2013 真题
给:
求真值。(Any Docs)
拆成:
所以:
阶码字段:
实际指数:
尾数:
于是:
做这种题最快技巧
十六进制不要全部转十进制。
只需要转换:
三个字段。
二十五、IEEE 真题第三类:规格化与非规格化
这已经连续成为考点。
2023 真题
机器数:
阶码全 0、尾数非 0。(Any Docs)
所以它不是普通规格化数,而是:
非规格化单精度公式不是:
而是:
这里最容易错的就是:
阶码全 0 时,实际指数不是简单算 。
非规格化数规定:
二十六、必须背下来的 4 个 float 边界
最小正规格化正数
最小正非规格化数
23 位尾数只有最低位为 1:
所以:
本站模拟题专门考了:
“最小正数”若没说“规格化”,答案应该考虑非规格化数,因此是 。(Any Docs)
最大有限正数
最大有限阶码:
所以:
最大有效数:
所以:
即:
这正是 2012 真题。(Any Docs)
二十七、题型 8:哪些十进制小数可以精确表示?
2021 真题用:
考过。(Any Docs)
核心规律:
如果一个有限十进制数化成最简分数:
它能用有限二进制小数表示,当且仅当:
例如:
分母:
所以可以精确。
而:
分母含:
所以二进制会无限循环。
因此:
这和十进制中的:
完全是同一个原理。
二十八、题型 9:float 到底能精确表示多大的整数?
单精度有效位:
因此所有绝对值不超过:
的整数都可以精确表示。
但是千万不要理解为:
超过 的整数一个也不能精确表示。
错。
例如:
本身当然能精确表示。
真正含义是:
超过以后,整数之间开始产生“空档”。
二十九、2024 真题:为什么 要用 double?
站内的 2024 真题给:
要求既保证整数精度,又尽量高效。(Any Docs)
对
32 位 int 范围:
完全够。
所以:
对
32 位 int 放不下:
float 虽然“范围”很大,但只有 24 位有效精度。
不能保证:
中的每个整数都精确。
double 有:
位有效精度,可以保证:
范围内整数精确。
所以:
这题非常重要
它考的是:
float 能表示:
量级,并不意味着这个范围内的整数一个不差全能存。
三十、题型 10:浮点加减运算全过程
标准过程:
这是必须背顺序的。
三十一、为什么对阶一定“小阶向大阶看齐”?
假设:
且:
应该把 改成:
也就是:
而不是把大阶数变小。
原因是尾数右移损失低位,虽然损失精度,但不会导致高位整数部分放不下。
三十二、2009 真题:浮点运算为什么最后才可能真正溢出?
站内 2009 年真题考查:
对阶、尾数相加、规格化之后,阶码加 1 最终越界。(Any Docs)
核心点:
尾数暂时出现:
本身不等于“浮点数溢出”。
可以右规:
所以:
只有:
也无法表示时,才真正上溢。
三十三、2015 真题:哪些步骤可能导致阶码越界?
真题考了四个判断。(Any Docs)
总结成表:
| 操作 | 对阶码影响 |
|---|---|
| 对阶 | 小阶增大到大阶,一般不会产生新越界 |
| 左规 | 阶码减小 |
| 右规 | 阶码增加 |
| 舍入进位 | 可能再次右规 |
| 连续左规 | 可能下溢 |
| 右规/舍入 | 可能上溢 |
所以:
更准确地说,是检查它们造成的阶码变化。
三十四、题型 11:为什么“大数 + 小数 = 大数”?
这是真题和模拟题非常喜欢出的“浮点违反数学直觉”。
假设 float 附近的数是:
单精度有效精度 24 位。
在数量级:
相邻 float 的间距为:
所以:
这意味着:
附近的 float 不是:
而类似:
因此加:
根本不足以跨越半个 ULP。
结果舍入回:
本站中王道模拟题用
float f = 2.5 + pow(2,33);
f = f - pow(2,33);考的就是这个现象,最终得到 0,而不是 2.5。(Any Docs)
三十五、必须掌握 ULP
对于规格化单精度 float,在:
范围内,有效尾数 23 位,因此相邻数间隔:
double:
这个公式可以秒杀大量“某整数能不能精确表示”“加多少会被吞掉”的题。
三十六、题型 12:舍入到最近、偶数优先
2017 年大题是这一点的经典应用。
定义:
当:
数学结果:
二进制就是:
共有:
个有效位。
但 float 只能保留:
位。
这时附近恰好两个可表示数:
和:
33554431 在正中央。
IEEE 754 默认:
于是选最低有效位为“偶”的那个:
这正是站内 2017 综合题解释的重点。(Any Docs)
三十七、题型 13:C 语言整数扩大——符号扩展与零扩展
这个极高频。
signed 扩大
例如:
short → int负数必须保持数值不变。
所以:
即高位复制原符号位。
例如:
16 位补码:
扩展到 32 位:
仍是:
这正是 2009 真题。(Any Docs)
unsigned 扩大
高位补 0:
例如 2012 真题:
是 unsigned short:
转 unsigned int:
而绝不能写成:
因为那会改变数值。(Any Docs)
三十八、题型 14:宽整数 → 窄整数
408 常采用机器级规则:
例如 2024 真题:
int i = 32777;
short si = i;
int j = si;(Any Docs)
有:
转 16 位 short:
最高位为 1。
按 16 位补码:
再扩回 int:
所以答案:
三十九、这类题万能算法
遇到:
大位宽 → 小位宽 → 大位宽一定:
第一步:截断
第二步:按目标类型重新解释
signed:
unsigned:
第三步:再扩展
signed:
unsigned:
这一套路非常稳定。
四十、题型 15:signed ↔ unsigned 同位宽转换
这是非常容易被骗的地方。
例如 2016 真题:
short si = -32767;
unsigned short usi = si;位宽相同。
的 16 位补码:
位串没变:
只是重新按 unsigned 解释:
所以:
也可直接用模:
得到:
(Any Docs)
四十一、无符号整数的本质就是模运算
位 unsigned:
因此:
不是:
而是:
对于 32 位:
这会直接引出 2017 年那个非常经典的 unsigned 死循环。
四十二、2017 综合题:为什么 unsigned 会死循环?
程序条件中含:
i <= n - 1而:
且 为 unsigned。(Any Docs)
于是:
不是:
而是:
所以条件相当于:
i <= 0xFFFFFFFFU而 本身也是 unsigned。
当:
再加 1:
于是:
永远满足条件。
形成死循环。
核心知识
这也是 C + 计组最典型的交叉题。
四十三、题型 16:int、float、double 互转
这个表必须彻底理解。
| 转换 | 典型后果 |
|---|---|
| int → float | 范围一般够,但可能丢精度 |
| int → double | 32 位 int 可精确 |
| float → double | 精确扩展 |
| double → float | 可能舍入,也可能溢出 |
| float/double → int | 去掉小数部分,还需检查范围 |
为什么:
32 位 int 只有大约:
个二进制数量级。
float 最大指数非常大,所以:
int → float 通常不是“范围不够”,而是“有效位不足”。
模拟题也专门考了这个区别。(Any Docs)
四十四、2010 真题:类型转换是否可逆
真题考过类似:
i == (int)(float)i
f == (float)(int)f
f == (float)(double)f
d + f - d == f(Any Docs)
逐个理解。
int → float → int
如果整数可被 float 精确表示:
仍一样。
float → int → float
例如:
转 int:
小数没了。
再转回:
显然:
float → double → float
double 精度更高。
原 float 的所有有效位都能完整保存。
所以:
通常能够精确恢复原 float。
数学:
计算机未必。
如果:
则对阶后 被完全舍掉:
随后:
所以:
这说明:
四十五、浮点数为什么不满足结合律?
例如:
和:
每一步都可能:
因此两个计算路径产生的误差不同。
所以一般:
类似地:
也未必等于:
这不是 CPU 算错,而是:
四十六、题型 17:乘法算法与硬件实现
2024 真题直接考整数乘法实现。(Any Docs)
例如:
编译器完全可以转为:
即:
同理:
可以:
所以常数乘法经常可以优化成:
四十七、没有乘法器能不能乘?
当然可以。
若:
其中:
则:
所以只要有:
就能乘。
这也是 2020 综合题明确考查的核心。(Any Docs)
四十八、三种乘法实现速度
2020 真题比较过三种情况:
软件实现
很多条:
判断
移位
加法
循环
分支需要反复取指、译码。
通常最慢。
一条乘法指令,但内部复用 ALU
CPU 内部进行很多轮:
比软件快。
阵列乘法器
大量组合逻辑并行产生部分积。
通常最快。
因此:
这里的 表示速度。
四十九、Booth 补码乘法
模拟题还专门考了 Booth 一位乘法。(Any Docs)
检查:
规则:
| 两位 | 操作 |
|---|---|
| 00 | 不加不减 |
| 01 | 加被乘数 |
| 10 | 减被乘数 |
| 11 | 不加不减 |
然后:
为什么 Booth 很重要?
因为类似:
这种大量连续 1,不需要真的加几十次,可以利用:
转化为少量加减。
五十、乘法溢出怎么判断?
unsigned
若两个 位数得到完整 位乘积:
只保留低 位。
无符号不溢出的条件:
高半部分只要有一个 1:
2020 大题明确考过这一点。(Any Docs)
signed
对于补码乘积,低 位若能正确表示真实结果,高 位必须恰好是低 位符号位的扩展。
若低位符号为 0:
若低位符号为 1:
因此:
否则 signed 乘法溢出。
五十一、2020 真题最漂亮的现象
给:
完整数学乘积:
64 位:
如果当 unsigned:
在 32 位 unsigned 范围:
内。
所以不溢出。
如果当 signed int:
低 32 位:
按补码解释:
但真实乘积是:
显然 int 放不下。
所以:
这再次说明:
机器比特相同,解释规则不同。
五十二、题型 18:补码除法的超级特殊情况
必须记:
数学结果:
但是 位补码最大正数只有:
因此:
例如 32 位:
而最大 int:
模拟题正是这样考的。(Any Docs)
这是整数除法中最著名的特殊溢出。
五十三、题型 19:2011 年整数综合大题——本章必会
站内这道题非常值得反复做。
题目设 8 位机器:
unsigned int x = 134;
unsigned int y = 246;
int m = x;
int n = y;
unsigned int z1 = x - y;
unsigned int z2 = x + y;
int k1 = m - n;
int k2 = m + n;然后问寄存器位模式、变量真值、加减器能否共用以及哪些运算溢出。(Any Docs)
这题实际上就是第 2 章整数部分的“总复习”。
第一步:unsigned 位模式
8 位:
第二步:unsigned 运算按模
模:
即:
而:
模:
所以:
第三步:相同位串重新解释成 signed
作为 8 位补码:
所以:
同理:
所以:
第四步:signed 运算
可表示:
但是:
小于:
所以:
机器低 8 位变成:
也就是两个负数加出了正机器结果。
这道题至少串起来了六个知识点
如果这道题真正吃透,整数部分已经掌握大半。
五十四、题型 20:2017 综合大题——整数和 float 的精度边界
这道题是本章另一道非常值得反复练的大题。
定义:
即:
分别使用 int 和 float 计算。(Any Docs)
它连续考:
int 最多精确到哪里?
要求:
所以:
得到:
float 最多保证精确到哪里?
因为:
二进制有:
个连续有效位。
float 只有:
位有效精度。
所以:
即:
这是非常漂亮的:
判断法。
五十五、题型 21:浮点什么时候变成正无穷?
单精度:
且:
代表:
所以:
就是:
而:
就是:
如果阶码全 1 且尾数非 0:
这几种机器数应该做到秒认。
五十六、题型 22:数制、ASCII、BCD 还要不要学?
要,但从站内真题分布看,并不像 IEEE 754、补码和类型转换那么密集。
建议掌握:
二进制 ↔ 八进制
每:
位一组。
二进制 ↔ 十六进制
每:
位一组。
因此看到:
最好直接按十六进制处理,不要展开成 32 个二进制位。
BCD
每 4 位编码一个十进制数字:
而:
不属于标准 8421 BCD 的十进制数字编码。
ASCII
本质是字符编码,不是数值的二进制表示。
例如字符:
'1'和整数:
机器表示完全不同。
这类知识更适合选择题查概念。
五十七、建议把整章压缩成 8 条解题算法
算法 A:补码真值
若最高位为 0:
若最高位为 1:
算法 B:整数溢出
先计算数学结果,再查:
选择题通常最快。
算法 C:OF
加法:
减法:
算法 D:类型转换
先问:
变宽:
signed → 符号扩展;
unsigned → 保持数值所需的零扩展。
变窄:
然后重新解释。
算法 E:IEEE 编码
算法 F:IEEE 解码
先看:
是否全 0 或全 1。
然后再决定使用:
还是:
绝对不要上来就直接算:
算法 G:float 精度
单精度:
double:
判断某整数是否“保证精确”时先数有效二进制位。
算法 H:浮点加减
五十八、几个最容易丢分的陷阱
| 错误认识 | 正确结论 |
|---|---|
| 补码最高位只是符号,不参与运算 | 符号位统一参与补码运算 |
| CF=OF | 两者分别用于 unsigned 与 signed |
| 尾数溢出就是浮点溢出 | 尾数可能右规后恢复 |
| float 尾数只有 23 位精度 | 有隐藏位,总精度 24 位 |
| float 能表示很大的数,因此大整数都精确 | 范围大 ≠ 精度高 |
| 最小 float 是 | 最小规格化才是,最小正数是 |
| 时指数就是 | 非规格化实际按 |
| int→float 一定精确 | 可能舍入 |
| float→double 会丢精度 | 可以精确扩展 |
| unsigned 减法能得到负数 | 实际按模 回绕 |
| 算术右移永远等于 C 的除以 2 | 对负奇数舍入可能不同 |
| 左移就是乘 2 | 不溢出时才成立 |
| signed 和 unsigned 用不同加法器 | 完全可以共用 |
五十九、根据现有真题,后续最值得防的变式
结合站内的真题和模拟题,下面几种组合尤其有 408 风格。
预测 1:IEEE 754 + 小端存储
先给一个浮点数:
要求算出 IEEE 机器数,然后问:
若从地址 开始按小端存储,地址 中是什么?
本站模拟题已经出现了类似“浮点机器数 + 小端字节存放”的组合,因此很值得练。(Any Docs)
核心:
注意:
小端只改变字节在内存中的顺序,不改变一个字节内部位的顺序。
预测 2:signed/unsigned + 比较指令
例如:
int x = -1;
unsigned y = 1;
if (x < y)先发生通常算术转换。
可能被转成 unsigned:
于是比较变成:
为假。
这一类能把:
串起来。
预测 3:float 精度 + 循环累计
例如连续:
问什么时候:
对于单精度 float,一旦数足够大:
再加 1 就可能被舍掉。
这是 2017 真题思想非常自然的升级。
预测 4:乘法低位一致性
给两个 位位串 ,分别:
- 按 signed 相乘;
- 按 unsigned 相乘;
问低 位是否相同。
核心:
整数机器运算本质:
所以低 位乘积具有很强的一致性。
但是:
这是很容易出的辨析点。
六十、最后给出一张“第 2 章考场决策图”
遇到机器数,第一件事问:
如果是整数:
如果发生加减:
如果发生类型转换:
如果是 float:
然后第一眼检查:
都不是才按:
如果发生浮点运算:
如果题目问:
为什么数学上相等,程序里不相等?
优先想到:
本章复习优先级
若以 408 提分为目标,建议第 2 章按以下顺序复习:
其中最值得反复重做的几道真题是 2011 整数综合题、2017 int/float 综合题、2020 乘法综合题、2010 类型转换题、2015 浮点运算判断题、2023 非规格化浮点数题、2024 数据类型选择题。这些题基本能把第 2 章最核心的命题链全部覆盖。(Any Docs)