上学期期末前一周,一个软件工程专业的学弟抱着一沓《计算机组成原理(微课版)》的习题来找我,说第2章的题他做了三遍,答案还是跟群文件里流传的那份对不上。我翻了他的本子,发现错的题几乎全落在同一类地方:补码的边界值、溢出判断的符号位、浮点数的阶码换算。这其实不是他不会做题,是这门课第2章有一条很陡的隐式台阶——教材正文讲的是定义,习题考的是定义之间的转换和边界,中间那一步没人替你说破。所以我把第2章课后习题按知识块重新捋了一遍,把我自己做题时的推演过程、容易翻车的位置、以及那些"答案给个结果、过程全跳过"的题目的完整演算写下来,给正在啃计算机组成原理的同学一份能直接对着抄思路的参考。
1. 第2章习题的命题地图:先弄清你在跟什么题目较劲
1.1 四个考区:习题其实只在考四件事
不同版本的《计算机组成原理》章节切法不一样。白中英体系里第2章是"运算方法和运算器",唐朔飞体系里第2章讲的是计算机的发展与应用,而市面上几本"微课版"教材,第2章基本都落在数据表示与运算这块地上。你如果拿着"微课版"的册子,第2章的内容大概率是:数制与编码、定点数的原码反码补码移码、定点加减运算与溢出判断、浮点数的表示与运算、以及运算器中的加法器和进位链。
这四个模块对应到习题上,出题形式非常固定。数制与编码部分考进制互转和小数精度;机器数部分考原反补移的互转和表示范围;定点运算部分考补码加减、溢出判断、移位;浮点部分考格式拆解、规格化、浮点加减法的五个步骤;加法器部分考先行进位公式和进位延迟估算。把这四块的解题模板各自跑通一遍,第2章的习题基本就没有陌生题了。
1.2 版本与题号差异:为什么你手里的答案跟题目对不上
这是我见过最多的困惑来源。同名的"第2章课后习题答案"在群里传来传去,经常出现三四个版本,题号一样但内容对不上。原因有三个:一是印刷版次不同,同一本书的第二版和第三版会增删题目,第 2-7 题在旧版里是浮点题,在新版里可能换成了加法器题;二是章节归属调整,有的版本把"校验码"放在第2章末尾,有的版本把它挪到了存储系统那一章;三是答案在传播过程中被抄错,尤其是浮点数的十六进制表示,抄漏一位尾数就会差出十万八千里。
我的处理办法是:不要按题号对答案,按知识块对。拿到一份答案,先看它讲的是补码还是浮点,再去找自己册子里对应的题。具体来说,你可以把第2章习题先归成下面这张表,再逐类去啃:
| 知识块 | 典型题干特征 | 核心考点 | 出现频率 |
|---|---|---|---|
| 数制与编码 | "将十进制数转成二进制""求 BCD 码" | 进制转换、精度截断 | 高 |
| 机器数表示 | "写出 x 的原码、补码、移码" | 原反补移互转、表示范围 | 极高 |
| 定点运算 | "用补码计算 x+y,并判断是否溢出" | 补码加减、溢出判断、移位 | 极高 |
| 浮点数 | "写出 IEEE 754 单精度表示""求浮点加减结果" | 格式拆解、规格化、对阶 | 高 |
| 加法器与进位 | "写出 C4 表达式""估算进位延迟" | 先行进位、进位结构 | 中 |
1.3 别把后面章节的热词带进来
搜这门课的时候,你一定会撞上"数据相关""结构相关""组间串行进位"这几个词。这里得拆清楚:"组间串行进位"确实是第2章加法器部分的内容,属于本章;而"数据相关""结构相关"是流水线章节讲指令相关性的东西,跟第2章没有关系。如果你拿着一道流水线相关的题去翻第2章的知识点总结,当然是找不到思路的。先定位章节,再定位知识块,这个顺序不能反。
2. 机器数转换与表示范围:原码、反码、补码、移码的互转与边界
2.1 补码"取反加一"背后的模运算逻辑
几乎所有教材都会告诉你,负数的补码等于"符号位不变、数值位取反加一"。但如果你只是背这句话,遇到"补码 10000000 的真值是多少"这种题就会卡住。补码的本质是模运算:字长 n 位时,模是 2ⁿ,负数 x 的补码就是 2ⁿ + x,也就是 2ⁿ − |x|。
用这个定义去理解"取反加一",一切就顺了。以 8 位字长为例,-45 的补码是 256 − 45 = 211,写成二进制是 11010011。而"45 的二进制 00101101 取反得 11010010,加一得 11010011",结果完全一致。为什么是取反加一?因为对于任意 n 位二进制数 A,取反的结果是 (2ⁿ − 1) − A,再加一就得到 2ⁿ − A。这就是"取反加一"的全部来历。
理解了模运算,还会顺带解决另一个高频疑问:为什么补码里零只有一个。原码里 +0 是 00000000,-0 是 10000000,两个编码对应同一个真值;反码里是 00000000 和 11111111,同样是两个。而补码里,-0 按定义应该表示为 2ⁿ − 0 = 2ⁿ,一个 n 位编码根本装不下 2ⁿ,溢出位被丢掉,只剩下 00000000,跟 +0 撞在了一起。这不是巧合,是模运算的必然结果,也是补码比原码反码更好用的根本原因——判零不需要特判。
2.2 表示范围与边界值:三个必须刻进脑子里的数
表示范围是第2章的送分题,也是最容易丢分的题,因为边界值太反直觉。n 位(含一位符号位)补码的取值范围是 −2ⁿ⁻¹ 到 2ⁿ⁻¹ − 1,比原码和反码多出一个数。8 位补码的范围是 −128 到 +127,而不是对称的 −127 到 +127。
三个必须记住的边界:
- 最小负数:8 位补码里是 10000000,真值是 −128,它的原码和反码都无法表示。这一点经常出判断题。
- 最大正数:8 位补码里是 01111111,真值是 +127。
- 负一的补码:全 1,8 位是 11111111。这是个很好用的校验锚点,算完补码顺手看一眼是不是全 1,能筛掉一大半粗心错。
提示:题目里如果出现"负数补码比原码多表示一个数",指的是多出最小负数那一个,不要理解成"负数范围不对称所以正负个数差 1"之外的别的意思。
2.3 移码为什么只用来表示阶码
移码的定义是把补码的符号位取反,等价于 [x]移 = 2ⁿ⁻¹ + x,其中 n 是移码的字长。它最大的特点是保持了真值的大小顺序:把移码当成无符号数去比较,谁大谁的本来真值就大。原码、反码、补码都不具备这个性质——补码的负数部分符号位为 1,如果按无符号数比较,会比正数还大。
正因为这个性质,移码几乎只出现在一个地方:浮点数的阶码。浮点加减法里第一步就是对阶,比较两个数的阶码谁大谁小,如果阶码用补码存,比较电路就得先判断符号位再比较,多一层逻辑;用移码存,直接当无符号整数比大小,硬件省事。这就是"移码为什么只用于阶码"这道简答题的标准答案,但你要答出"因为它便于比较大小",而不是只答"教材就是这么规定的"。
这里有个极易混淆的点必须单独说:通用移码的偏置是 2ⁿ⁻¹,而 IEEE 754 单精度阶码的偏置是 127,也就是 2⁸⁻¹ − 1。两者差 1。考试里如果题目说"阶码用移码表示",默认指偏置 2ⁿ⁻¹;如果说"按 IEEE 754 标准",就必须用 127。这个坑我在批改作业时见过太多次了。
2.4 典型习题的分步解法
按上面这套逻辑,动手做一遍。题目给的是"设字长 8 位,求 x = −73 的原码、反码、补码和移码"。
第一步,先把绝对值转成二进制。73 = 64 + 8 + 1,所以 73 的二进制是 1001001,补齐到 7 位数值位是 1001001。
第二步,原码。符号位取 1,数值位照抄:11001001。这是最直观的一步。
第三步,反码。符号位保持 1,数值位逐位取反:10110110。
第四步,补码。在反码基础上加一:10110110 + 1 = 10110111。顺手校验一下:8 位补码 10110111 的真值是 256 − 183 = 73,符号为负,即 −73,对上了。
第五步,移码。把补码的符号位取反:00110111。也可以直接用 128 + (−73) = 55 来验证,55 的二进制是 00110111,一致。
这套流程的关键在于每一步都要回头验算一次。尤其是补码,用"2ⁿ − |x|"这条路径独立算一遍,两条路结果一致才落笔。我自己的习惯是:只要涉及负数补码,就在草稿纸边上写一行 256 − |x| 的结果做双重确认,这一个小动作能挡掉八成以上的符号位错误。
3. 定点加减运算与溢出判断:三种判溢出法怎么选、怎么算
3.1 溢出不是"算错了",是"装不下"
初学者最容易把溢出和计算错误混为一谈。溢出的定义是:运算结果的真值超出了机器字长能表示的范围,而不是算错了。两个 8 位补码正数相加,结果如果超过 127,硬件就会给出一个看起来像负数的结果——那是高位被挤掉了,不是运算器算错了。
这个区分直接影响答题话术。题目问"结果是否溢出",你要答的是"真值超出 8 位补码表示范围,发生正溢出",而不是"结果错误"。判溢出本身有三套方法,都要会,因为题目可能指定用哪一套。
3.2 单符号位进位法:一个异或就能定
原理很简单:把符号位也当数值一起加,会产生两个进位——最高数值位向符号位的进位 C_f和符号位向更高位的进位 C_0。这两个进位不同,就说明符号位被数值部分的进位"污染"了,结果必然越界。判断条件写成式子就是C_f ⊕ C_0 = 1 时溢出。
举个例子,8 位补码计算 01010101 + 01100011。数值部分相加是 1010101 + 1100011,符号位都是 0。逐位加下来,结果编码是 10111000,同时数值位向符号位产生了进位、符号位也向外产生了进位。两个进位都是 1,异或为 0,按这条规则判断无溢出——但这里明明溢出了!问题出在哪?我特意拿这道题做演示,是因为它踩的正是这个方法的使用前提:进位法只适用于同号相加的情况。两个正数相加符号位变 1,或者两个负数相加符号位变 0,才叫溢出;异号相加永远不会溢出。
重新来:01010101(+85)加 01100011(+99),真值 184 超过 127,正溢出。用双符号位法验证:001010101 + 001100011 = 010111000,双符号位是 01,正溢出,对上了。所以进位异或法在答题时,必须先判断两个操作数是否同号,同号才有溢出的可能。
3.3 双符号位(变形补码)法怎么落笔
变形补码就是把符号位扩成两位:正数是 00,负数是 11。运算时两位符号位一起参与,结果的两位符号位若为 00 表示结果为正且正确,11 表示结果为负且正确,01 表示正溢出,10 表示负溢出。因为 01 和 10 这两种组合在正常结果里根本不会出现,所以判据非常干净。
用同一组数:+85 的变形补码是 001010101(8 位数值位,2 位符号位),+99 是 001100011,相加得 010111000。两位符号位是 01,正溢出,结论明确。如果是两个负数 −85 和 −99 相加:110101011 + 110011101,加上进位后得到 101000 ... 符号位为 10,负溢出。
这套方法的好处是结果符号位自身就携带了溢出信息,不需要额外算进位。缺点是在手算时容易把两位符号位当成一个符号位处理,移位的时候忘记两位置一起动。我的建议是:草稿纸上把两位符号位用括号圈起来,例如写成 (00)1010101,视觉上和其他位隔开,出错率会明显下降。
3.4 移位运算:三种移法各自的丢失位规则
移位是第2章另一类高频题。三种移位要分清:
- 算术移位:符号位不动,数值位整体移动。左移时低位补 0;右移时高位补符号位(正数补 0,负数补 1)。算术左移一位相当于乘 2,右移一位相当于除 2。
- 逻辑移位:不管符号,整体移动,左移低位补 0,右移高位补 0。常用于无符号数的位操作。
- 循环移位:移出的位补回到另一端,分带进位位和不带进位位两种。
这里有个必须点出来的坑:算术右移一位对负数来说,效果是"除以 2 之后向下取整",不是精确除 2。举个具体的例子,定点小数补码 1.0101(真值 −0.1011,也就是 −11/16),算术右移一位得 1.1010,还原成真值是 −6/16。而 −11/16 ÷ 2 = −11/32,并不等于 −6/16。差在哪?补码右移是把最低位直接丢掉,丢掉的这一位永远不会"借"回来,所以负数右移的结果比真正的商更小(更负)。这个结论在判断题里经常出现,写答案的时候一定要提"低位被舍弃"这个前提。
算术左移则要注意溢出。判定规则是:左移前,若符号位与最高数值位相同,左移不溢出;不同则溢出。上面那个 1.0101,符号位是 1,数值位最高位是 0,两者不同,所以左移一位就会溢出——真值 −11/16 乘 2 得 −1.375,确实超出了 1 位符号位的定点小数表示能力。
3.5 典型习题详解:补码加减与结果校验
题目:设字长 8 位,已知 x = +1011,y = −1101,用补码计算 x − y,并说明是否溢出。
第一步,把两个数补足 8 位并写出补码。x = +1011,符号位 0,数值位补齐成 0001011,得 [x]补 = 00001011。y = −1101,绝对值 1101 补齐成 0001101,取反得 1110010,加一得 1110011,加上符号位 1,得 [y]补 = 11110011。
第二步,把减法转成加法。[x − y]补 = [x]补 + [−y]补。[−y]补 就是把 [y]补 连符号位一起取反加一:11110011 取反得 00001100,加一得 00001101。
第三步,相加。00001011 + 00001101 = 00011000。
第四步,校验。结果符号位是 0,为正数,真值就是 00011000 = 24。独立验算:11 − (−13) = 24,一致。两个操作数一正一负,属于异号相加,不可能溢出,这一步的判断可以直接写"异号相加,无溢出"。
注意:做补码减法时,不要忘了 [−y]补 是对 y 的补码"连符号位一起"取反加一,而不是只对数值位操作。只改数值位是初学者最常犯的错误,改完符号位不变,结果直接错一个数量级。
4. IEEE 754 浮点数:从格式拆解到加减法五步
4.1 单精度三段式:符号、阶码、尾数
IEEE 754 单精度浮点数固定 32 位,切成三段:第 31 位是符号位 S,第 30 到 23 位是 8 位阶码 E,第 22 到 0 位是 23 位尾数 M。真值的计算公式是:
x = (−1)^S × 1.M × 2^(E − 127)
做题时建议养成习惯,先把 32 位按 1-8-23 的长度画三条竖线隔开,再往格子里填。这个动作看着傻,但它能防止你把阶码和尾数的位数数错——32 位里错一位,后面全错。
4.2 隐藏位、偏置 127 与规格化
规格化浮点数的尾数形式固定为 1.xxxxx,最左边那位 1 不存进机器,默认存在,这叫隐藏位。所以尾数段存的其实是小数点后的 23 位,实际有效精度是 24 位。
阶码用偏置 127 的移码表示,也就是说存进去的 E 等于真实阶码 e 加 127。为什么是 127 而不是 128?因为 IEEE 754 把 E 全 0 和全 1 留给了特殊值,剩下的 E 从 1 到 254 对应真实阶码 −126 到 +127,这个区间是正负对称的,所以偏置取中间值 127。理解了这一点,"为什么 IEEE 754 的偏置是 127 而通用移码是 128"这道简答题就能自己推出来了。
4.3 四个特殊值区域
尾数和阶码的组合还留了几个特殊编码,考试必考:
| 阶码 E | 尾数 M | 表示含义 |
|---|---|---|
| 全 0 | 全 0 | 正负零 |
| 全 0 | 非 0 | 非规格化数,用于表示极小的数 |
| 全 1 | 全 0 | 正负无穷 |
| 全 1 | 非 0 | NaN,非数字 |
非规格化数的存在是为了让 0 和最小规格化数之间平滑过渡,避免精度断崖。这一点在很多答案里被漏掉,但简答题如果问"为什么需要非规格化数",答"为了表示比最小规格化数更接近零的数,使精度在零附近连续衰减"才算完整。
4.4 浮点加减法的执行顺序与对阶方向
浮点加减法的五个步骤是:对阶、尾数加减、规格化、舍入、溢出判断。顺序不能乱,每一步的目的要说清楚。
对阶的方向是小阶向大阶看齐,这一步是整道题的灵魂。为什么不能大阶向小阶看齐?因为大阶向小阶看齐意味着尾数要左移,左移会把高位的有效数字挤出去,直接损失有效位;而小阶向大阶看齐是尾数右移,丢掉的是低位,损失的是精度末尾几位。两害相权取其轻,所以统一往大阶靠。
规格化分两种动作:左规用于尾数出现 0.0xxx 这种形式(符号位与最高数值位相同),尾数左移、阶码减 1,直到符号位与最高数值位不同;右规用于尾数加法后出现溢出(形如 1x.xxx 或 0x.xxx 加倍),尾数右移一位、阶码加 1。舍入方法有 0 舍 1 入、恒置 1、就近舍入三种,题目没指定就用 0 舍 1 入。
4.5 典型习题详解
第一题:把 −20.75 转成 IEEE 754 单精度表示。
先把绝对值转成二进制:20.75 = 16 + 4 + 0.5 + 0.25 = 10100.11。规格化成 1.xxx 形式:小数点左移 4 位,得 1.010011 × 2⁴。所以 S = 1(负数),真实阶码 e = 4,E = 4 + 127 = 131,二进制是 10000011。尾数段取小数点后的 010011,补齐 23 位:01001100000000000000000。
三段拼起来:1 10000011 01001100000000000000000,按 4 位一组转十六进制:
- 1100 = C
- 0001 = 1
- 1010 = A
- 0110 = 6
- 后面全是 0
结果是 0xC1A60000。
反向验算一遍:0xC1A60000 展开,S = 1,E = 10000011 = 131,e = 4,尾数 1.010011 × 2⁴ = 10100.11 = 20.75,符号为负,得 −20.75,完全对上。
第二题:浮点加减法。设阶码 4 位(含 1 位符号位,补码),尾数 7 位(含 1 位符号位,补码),x = 2³ × 0.1101,y = 2¹ × (−0.1010),求 x + y。
对阶:3 > 1,y 的阶码要向 3 看齐,尾数右移 2 位。−0.1010 右移两位得 −0.001010,写成补码是 1.110110(取反 1.110101 加一得 1.110110)。x 的尾数 0.1101 补齐成 0.110100。
尾数相加:0.110100 + 1.110110 = (1)0.101010,最高位的进位丢弃,得 0.101010。
规格化检查:符号位 0,最高数值位是 1,两者不同,已经规格化,不需要左规,也不需要右规。阶码保持 0011。
结果:0.101010 × 2³。验算:0.101010 的真值是 0.65625,乘 8 等于 5.25;左边 6.5 + (−1.25) = 5.25,一致。
第三题:需要左规的情形。x = 2⁰ × 0.1101,y = 2⁰ × (−0.1011),求 x + y。两个数阶码相同,不用对阶,直接加尾数:0.1101 + (−0.1011),补码分别是 0.110100 和 1.010100。相加得 (1)0.001000,丢弃进位得 0.001000。
此时符号位 0,最高数值位 0,相同,属于非规格化,需要左规。左移一位得 0.01000,阶码减 1 变成 −1;还是不符合 0.1xxx 的形式,再左移一位得 0.10000,阶码减到 −2。结果 0.10000 × 2⁻² = 0.125,验算 0.8125 − 0.6875 = 0.125,正确。
提示:左规时尾数每左移一位,阶码必须减 1;右规时尾数每右移一位,阶码必须加 1。方向写反是浮点题里最常见的低级错误,而且检查的时候很难发现。
5. 加法器与进位链:串行进位、组内并行组间串行的计算题
5.1 Gi、Pi 的物理含义与先行进位公式
并行进位这一块,公式推导是很多人的噩梦,其实把两个辅助函数的物理含义搞懂,公式是自然长出来的。
对第 i 位,定义G_i = A_i · B_i,叫进位产生函数:当这一位的两个加数都是 1 时,本位一定向高位产生进位,跟低位有没有进位毫无关系。定义P_i = A_i ⊕ B_i,叫进位传递函数:当这一位两个加数不同(一个 0 一个 1)时,本位的进位输出完全取决于低位是否送来了进位——低位进位来了就把它传下去,没来就输出 0。如果两个加数都是 0,本位永远不产生进位,进位链在这里断掉。
有了这两个函数,进位表达式就统一成:
C_(i+1) = G_i + P_i · C_i
从 C₀(最低位进位输入,加法时是 0)开始展开:
- C₁ = G₀ + P₀·C₀
- C₂ = G₁ + P₁·G₀ + P₁·P₀·C₀
- C₃ = G₂ + P₂·G₁ + P₂·P₁·G₀ + P₂·P₁·P₀·C₀
- C₄ = G₃ + P₃·G₂ + P₃·P₂·G₁ + P₃·P₂·P₁·G₀ + P₃·P₂·P₁·P₀·C₀
这就是 4 位先行进位链的全部公式。每个 C 都只依赖 G、P 和 C₀,而 G、P 又只依赖加数本位的输入,所以 C₁ 到 C₄ 可以同时算出来,不必一级一级等。
5.2 串行进位加法器的延迟估算
串行进位(也叫行波进位)结构最简单:每一级的进位输出接下一级的进位输入,进位像波浪一样从最低位一路推上去。代价是延迟线性增长。
延迟怎么算,取决于教材采用的模型。常见的做法是约定"每经过一级门延迟记为 1t":全加器内部,从加数输入到产生 G、P 用一级异或门(按 1t 算),从 G、P 和低位进位到产生本位进位用一级与门加一级或门(2t),从进位到产生本位和再用一级。按这个模型,n 位串行加法器的进位传播延迟大约是2n·t,再加上最前面算 G、P 的 1t 和最后求和的 1t,总的加法时间接近 (2n + 2)t。16 位加法器算下来,光进位传递就要 32t 左右。
如果你的教材用的是"每级门 1t、异或门 2t"的模型,或者把与门或门合并成一级算,数值会不一样。做题时一定要按自己教材的模型来,不要跨版本套数字,这是我在答疑时反复强调的一点。
5.3 组内并行、组间串行、组间并行三种结构的对比
先行进位链的扇入不能无限大。C₄ 的表达式里有 5 个乘积项,C₈ 会有 9 项,C₁₆ 会有 17 项——门电路的扇入根本扛不住。所以实际设计里要把加法器分组:组内用先行进位,组间再决定怎么连接。
这就产生了三种经典结构:
| 结构 | 16 位进位传递延迟(按每级门 1t 估算) | 硬件代价 | 典型用途 |
|---|---|---|---|
| 纯串行进位 | 约 32t | 最低 | 位数很少、成本优先 |
| 组内并行、组间串行 | 约 8t(4 组 × 2t) | 中等 | 通用处理器的 ALU 常见折中 |
| 组内并行、组间并行 | 约 4t(组内 2t + 组间 2t) | 最高 | 高性能、宽位宽场景 |
组内并行、组间串行的做法是:16 位分成 4 组,每组 4 位,组内用上面那套公式同时算出 C₁ 到 C₄;但第一组算出的 C₄ 要作为第二组的进位输入,第二组才能算自己的内部进位,如此逐组传递。所以延迟是"每组 2t × 组数"。
组间并行则再往上一层做文章:把每一组看成一个大位,定义成组进位产生函数G* = G₃ + P₃G₂ + P₃P₂G₁ + P₃P₂P₁G₀,成组进位传递函数P* = P₃P₂P₁P₀。用 G* 和 P* 取代单个位的 G、P,套进同一套先行进位公式,就能一次性算出 C₄、C₈、C₁₂、C₁₆。这样组间的等待也被消掉了,代价是额外一组逻辑门。
5.4 典型习题详解:从公式到延迟估算
第一题:写出 4 位先行进位加法器 C₄ 的表达式,并说明它所依赖的输入。
按 5.1 的展开式直接写:C₄ = G₃ + P₃G₂ + P₃P₂G₁ + P₃P₂P₁G₀ + P₃P₂P₁P₀C₀。它依赖的是四组 G、P 和最低位进位 C₀,全部与低位进位链无关,所以可以和 C₁、C₂、C₃ 并行产生。答题时补一句"各乘积项分别对应进位从不同位置产生并被逐级传递到 C₄ 的情形",比只写公式更容易拿全分。
第二题:某 16 位加法器采用 4 位一组、组内并行进位、组间串行进位结构,设每组内部产生全部进位需要 2t,最低位到第一组进位输出 C₄ 的延迟为 2t,估算 C₁₆ 的延迟。
组内进位是并行产生的,C₄ 在 2t 时刻到位。C₄ 作为第二组的进位输入,第二组内部也是先行进位,再过 2t 产生 C₈。依此类推,C₁₂ 在 6t 时刻,C₁₆ 在 8t 时刻。所以 C₁₆ 的延迟约 8t。
对比纯串行结构:同样的 16 位,串行需要约 32t。并行进位的价值就在这里——用多一组逻辑门,把进位延迟压到四分之一。
第三题:如果改成组间也并行,延迟怎么变?
组间并行时,四组的进位 C₄、C₈、C₁₂、C₁₆ 由顶层先行进位链一次算出,顶层本身也是一级与门加一级或门,约 2t。所以 C₁₆ 的延迟约 2t(组内)+ 2t(组间)= 4t。
答这类题的时候,写清"我按每级门 1t 建模",再给结论,就不会因为教材模型不同被判错——阅卷看的是推理过程,不是一个绝对值。
6. 第2章习题里最容易翻车的细节清单
6.1 高频错误归类
把批改和答疑里出现的问题归一下类,你会发现错误集中在下面这几处:
- 补码符号位忘记参与运算。补码加减法里符号位是当数值位一起加的,不能像原码那样单独处理。
- 求 [−y]补 时只对数值位取反。正确做法是整个编码连符号位一起取反加一。
- 判溢出时没先看操作数符号。同号相加才可能溢出,异号相加直接写"不可能溢出"。
- 移位时符号位跟着动。算术移位里符号位是钉死的,只有循环移位才会把位绕回去。
- 浮点对阶方向写反。记住"小阶向大阶看齐",然后把理由写上,理由写对了方向基本不会错。
- IEEE 754 的偏置用成 128。单精度是 127,双精度是 1023,别混。
- 尾数隐含位忘记补。从 IEEE 754 反推真值时,尾数前面必须补上那个默认的 1,只有非规格化数才补 0。
- 左规右规时阶码方向搞反。左规减阶,右规加阶。
- 十六进制转换时四位一组从右往左分。从左边开始分组最容易错位。
- 答案只写结果不写过程。这类题几乎都是过程分占大头,结果对了过程空着照样扣分。
6.2 刷题顺序与二次校验方法
我自己的刷题顺序是:先集中刷机器数互转,一天刷透;再刷定点加减和溢出判断,这部分和机器数是强关联的,前面熟了这里会很快;然后攻浮点数,因为浮点是最独立也最容易忘的一块,适合单独拿一整段时间;最后做加法器和进位链的题。这个顺序的好处是每一步都在复用前一步的结论,不会出现"翻回去重学符号位"的情况。
二次校验我固定用三种手段:补码用模运算反算真值,把结果编码按 2ⁿ − |x| 的路子倒推一遍;浮点用十进制近似值验算,把结果还原成十进制大致比对一下量级,如果差出一个次方,肯定是阶码错了;加法器延迟用不同分组方式重算,比如把 16 位换成 8 位两组再算一次,看看结论符不符合规律。
6.3 习题和运算器实验的联动
第2章的习题里,加法器和进位链这块光靠纸笔其实很难建立起直觉。如果你手头有计算机组成原理与系统结构的实验仿真平台(比如很多学校在用的 COP 系列实验环境),可以拿它把 4 位先行进位加法器搭出来,把每一级的 G、P 和进位信号拉出来看波形。我在带实验课时发现,凡是先在仿真平台上把进位链的传播过程看过一遍的同学,回来做延迟估算题几乎不会错——因为"进位从哪里产生、被谁传递下去"这件事已经变成画面了,不再是纸上的一串公式。
另外提醒一句,很多学校的期末卷子会从课后习题里原题或者小改一版出题,尤其是补码运算、溢出判断和 IEEE 754 转换这三类。把这几类题做到不看答案能一口气写完、边写边能说出每一步的理由,第2章基本就稳了。我在实际操作中的体会是,这门课真正难的不是公式记不住,而是每一步"为什么这么做"没想清楚——把理由补齐之后,答案本身反而是最不用操心的部分。