运算方法与运算器:原码补码、溢出判断与课后题解析
前天晚上一个学弟发消息给我说《计算机组成原理微课版》第三章的课后题他刷了两遍合上书重做还是会在符号位上翻车原码、补码、反码、移码四个码换过来换过去容易乱补码加法的溢出判断也是靠死记。我回了一句你不是不会算你是没把“运算方法”和“运算器”这两条线串起来。这章叫运算方法与运算器表面上是四个码、四类运算实际考的是同一件事——硬件的运算器到底怎么把二进制算出来。这篇文章我就按课后题最常出现的几大题型把答案和推导过程一起拆开讲适合正在刷课后题、准备期末或者准备考研基础复习的人。## 1. 这一章的“骨架”数据表示、四类运算、运算器结构 第三章的内容看上去很杂但骨架就三条数据表示、算术运算、运算器实现。多数课后题也是围绕这三条线展开的理解了这个框架你才知道一道题考的是“机制”还是“电路”。 ### 1.1 四个码之间的关系不是背出来的 原码、反码、补码、移码所有教材都会给定义但真正算题时会发现转换关系其实是一条链 - 正数的原码、反码、补码一样 - 负数的反码是原码数值位按位取反 - 补码是反码再加 1 - 移码是补码的符号位取反。 从硬件角度看补码是最省事的表示方式。因为补码把减法变成加法符号位也当成数值位参与运算运算器里只需要一套加法器。移码则是为了让浮点数的阶码可以按无符号数比较大小所以浮点题里经常碰到。 课后题如果让你“写出 x 的原码、反码、补码和移码”不要一个一个硬算而是先写原码再推反码再推补码最后推移码。这样一条链走下来出错概率小很多。 ### 1.2 加、减、乘、除分别对应什么硬件套路 加减法对应加法器和进位链乘法对应“部分积累加 右移”原码一位乘和补码一位乘Booth 算法都是这个思路除法对应“移位 减法”的迭代过程恢复余数法和加减交替法本质是同一套比较逻辑。运算器结构题则常考 ALU、寄存器、数据通路以及进位方式对速度的影响。 这些内容在课后题里很少孤立出现通常是一道大题给你一串二进制数让你完成一种运算再问你结果是否溢出或者让你画出运算器的数据通路。所以复习的时候要主动把“数据表示”和“运算方法”连起来。 ### 1.3 我建议的刷题顺序 我通常会让学生按这个顺序过课后题 1. 先练码制转换和真值范围这是所有运算的基础 2. 再练补码加减法和溢出判断因为乘除法都要用补码 3. 接着是原码一位乘、补码一位乘重点观察部分积右移 4. 然后是除法恢复余数法能看懂加减交替法能写出步骤 5. 最后是浮点运算把对阶、求和、规格化、舍入、判溢出串起来。 这样每走一步都是在给下一步铺路不会出现“乘法算到一半符号位乱套”的问题。2. 码制转换和溢出判断题核心是“模”的概念课后题里最基础的题型就是给你一个十进制真值让你写出四种码再算两个补码相加判断是否溢出。这类题不难但特别容易在小数点、位长、符号位上丢分。2.1 典型题8 位字长求 (x-53D) 的四种码先把 53 转成二进制(53D 321641 00110101B)。因为是 8 位字长最高位留给符号位所以原码符号位为 1数值位不变得到10110101反码符号位不变数值位按位取反得到11001010补码反码加 1得到11001011移码补码的符号位取反得到01001011这里有一个很多初学者都会问的问题为什么补码要“反码加 1”因为补码的定义是模 (2^8) 意义下的余数表示。负数 (x) 的补码等于 (2^8 x)而 (-53) 对应 (256-53203)写成 8 位二进制正是11001011。“反码加 1”只是这个模运算的快速计算方式不是人为规定的技巧。2.2 典型题补码加法到底溢出了吗看一个经典题设 8 位字长补码表示求 (127D 1D)并判断是否溢出。(127D 01111111)(1D 00000001)相加得到10000000在补码里这是 (-128D)。一个正数加正数结果变成了负数显然不合理所以溢出。判断溢出不只有“正加正得负”这种直观方法还有两个更通用的判断标准最高有效位进位与符号位进位的异或结果为 1 时溢出。这个例子中最高有效位上的 (11) 产生进位而符号位 00 加上这个进位后不产生进位两者相异所以溢出。使用双符号位变形补码判断。把符号位扩展成两位运算后符号位变成01表示正溢出10表示负溢出。2.3 双符号位判断溢出的原理双符号位教材上写得比较抽象但实际操作很简单先给每个数添一个符号位副本比如127写0011111111写000000001相加得到010000000。两个符号位分别是 0 和 1也就是01这就是正溢出。为什么01就一定是溢出因为正常结果用两个相同的符号位表示00是正11是负。一旦运算结果的符号位变成01或10说明结果的数值部分增长到了符号位原来的字长已经装不下了。这个方法在乘除法、浮点运算里同样适用建议养成写双符号位做题的习惯。## 3. 加法器与进位链串行进位和组间串行进位的延迟估算 这一节课后题经常从“一位全加器”出发逐步让你推出串行加法器、并行进位加法器、组间串行进位加法器。很多人看到门电路就头疼其实抓住一个核心就行进位是逐位传还是提前算。 ### 3.1 一位全加器的逻辑表达式 一位全加器有三个输入两个加数 \(A_i\)、\(B_i\) 和低位进位 \(C_i\)两个输出本位和 \(S_i\)、向高位的进位 \(C_{i1}\)。 - \(S_i A_i \oplus B_i \oplus C_i\) - \(C_{i1} A_iB_i (A_i \oplus B_i)C_i\) 这里 \(A_iB_i\) 被称为进位生成函数 \(G_i\)它的含义是当两个加数都是 1 时无论低位有没有进位本位一定会向高位产生进位。\((A_i \oplus B_i)\) 被称为进位传递函数 \(P_i\)含义是当两个加数中只有一个为 1 时如果低位有进位进来就会原样传出去。 课后题如果让你“写出全加器表达式并说明含义”把 \(G_i\) 和 \(P_i\) 这两个名字写上基本能拿全分。 ### 3.2 4 位超前进位加法器的进位级联 串行加法器的问题在于进位要一位一位往上抬最坏情况是最低位进位一路传到最高位。超前进位加法器就是为了消除这种等待用逻辑直接把 \(C_1\) 到 \(C_4\) 同时算出来。 以 4 位为例假设 \(G_i A_iB_i\)\(P_i A_i \oplus B_i\)则 - \(C_1 G_0 P_0C_0\) - \(C_2 G_1 P_1G_0 P_1P_0C_0\) - \(C_3 G_2 P_2G_1 P_2P_1G_0 P_2P_1P_0C_0\) - \(C_4 G_3 P_3G_2 P_3P_2G_1 P_3P_2P_1G_0 P_3P_2P_1P_0C_0\) 这组公式不用死背理解规则就好\(C_i\) 的表达式里要么由某个高位位置的 \(G_j\) 直接产生要么由一串 \(P_j\) 把初始进位 \(C_0\) 传过来。写成“与或式”后所有进位可以在同一个周期内算完。 ### 3.3 16 位 ALU 采用组间串行进位的延迟估算 考试特别爱考“16 位 ALU 分成 4 个 4 位一组组内先行进位组间串行进位求最坏进位延迟”。 设每个 4 位组内部产生组进位的时间为 \(T\)组间进位传递时间也为 \(T\)。第一组需要 \(T\) 时间先算出组进位然后这个进位要依次传给第二组、第三组、第四组共经过后 3 个组间传递也就是 \(3T\)。总延迟约 \(T3T4T\)。 如果把 16 位全部采用行波进位每一位的进位都串联延迟约 \(16T\)这就能看出分组并行进位的优势。答题时要说明组内并行缩短了进位链长度组间串行只保留少量串行时间这是速度和复杂度之间的折中。4. 乘法器课后题原码一位乘和 Booth 算法的手算套路乘法是第三章课后题里的重头戏。原码一位乘相对简单补码一位乘Booth 算法则容易在“加还是减”上判断错。我建议每道题都用真实二进制数完整推一遍不要只看最终答案。4.1 典型题原码一位乘 (x-0.1101)(y0.1011)原码一位乘的核心思想是“符号位单独处理数值位按绝对值相乘”。先算符号位乘数、被乘数异号结果符号为负符号位为 1。接着算数值部分(0.1101 \times 0.1011)手算竖式如下0.1101 × 0.1011 --------- 0.1101 0.1101 0.0000 0.1101 --------- 0.10001111所以 (x \times y -0.10001111)写成原码为1.10001111。实际硬件流程是用乘数最低位判断是否加被乘数每次加完后把“部分积 乘数”整体右移一位。因为乘数和部分积最终拼成了乘积右移操作既是为了让部分积的一位落入乘数寄存器也是为了把结果逐步凑出来。4.2 Booth 算法补码一位乘到底看哪两位考试时 Booth 算法通常给你两个小数要求用补码乘法求积。常用判断表是当前乘数位 (y_i)附加位 (y_{i1})操作00不操作01加 [x]补10减 [x]补即加 [-x]补11不操作注意这里的“看两位”是从最低位和附加位开始每一步根据这两位的组合决定操作然后做一次算术右移。算术右移的意思是符号位保持不变这样补码的符号位不会因为右移而丢失。我建议考试时先用普通乘法验证结果。比如 (x0.1101)(y-0.1011)普通竖式算出来积为 (-0.10001111)那么补码形式就是1.01110001。做完 Booth 表之后如果结果不是这个数说明某一步的“加”或“减”判错了。4.3 这两道乘法题最容易踩的坑第一个坑是原码一位乘把符号位也拿去参与乘法运算。正确的做法是先做异或得到符号位数值位绝对值相乘最后再拼符号位。第二个坑是 Booth 算法右移时用了逻辑右移。补码是负数时右移必须在高位补 1也就是算术右移。很多人在这一步把1001右移成0100结果整个结果都不对。第三个坑是漏掉乘数最低位右侧的附加位。Booth 算法初始化时一定要在乘数最低位后面补一个 0每一步判断的是当前最低位和这个附加位的组合不是一个位。没有附加位整个判断循环就错位。5. 除法器课后题恢复余数法的完整推演除法比乘法更抽象因为它不是单纯的“加加加、移移移”而是每一步都要判断“够不够减”。恢复余数法和加减交替法是本节两大考点。5.1 典型题原码恢复余数法 (x0.0110)(y0.1100)设被除数 (x0.0110)除数 (y0.1100)。我先用竖式感觉一下结果(0.0110 / 0.1100 0.1000)余数为 0。恢复余数法流程余数寄存器 R 初始值为被除数0.0110商寄存器 Q 初始为0000每一轮先让 R 左移一位然后减去除数 M如果减完后大于等于 0商上 1余数寄存器保留减后的结果如果减完后小于 0商上 0同时把减掉的除数加回来恢复到移位后的原始值所以叫“恢复余数”。完整过程如下步骤操作比较结果商初始R0.0110, M0.1100—Q0000第1轮R 左移为0.1100减 M 得0.0000≥0商1Q0001第2轮R0.0000左移减 M 得负0恢复商0Q0010第3轮R0.0000左移减 M 得负0恢复商0Q0100第4轮R0.0000左移减 M 得负0恢复商0Q1000最终商为0.1000余数为0.0000。验证一下(0.1000 \times 0.1100 0 0.0110)正确。这种题考的是对“够减/不够减”的循环理解所以我建议每轮都标注“恢复前”和“恢复后”的 R 值阅卷老师看了会觉得你很稳。5.2 加减交替法为什么可以省掉“恢复”加减交替法也叫不恢复余数法。它的思路是如果某一步不够减不要立刻把除数加回去而是把“减多了”的这个结果保留下一步用“左移后加除数”来修正。规则可以这样记上一步商 1下一步就减除数上一步商 0下一步就加除数。整个过程不断根据上一步的正负决定下一步的操作所以省去了反复恢复余数的步骤。从硬件角度来说恢复余数法的缺点在于“不够减”时要多做一次加法这既浪费时间也会让最坏执行时间不确定。加减交替法让每一步固定就是一次移位加一次加/减法执行时间稳定控制逻辑也简单。5.3 做除法题时的符号位和余数修正除法题和乘法一样符号位单独处理。原码除法里商符号 被除数符号异或除数符号余数符号通常和被除数一致。这里有一个容易忽略的细节如果题目要求余数不能只写商。余数也有符号而且余数的位数可能需要修正。课后题里如果给了“原码一位除法”这个前提最终结果一般写成商用原码表示余数用原码表示符号位与被除数相同。题目没给符号位时可以先用正值算数值部分最后再补符号位这是我比较推荐的做法。6. 浮点运算题对阶、求和、规格化、舍入、判溢出浮点运算把整章知识都串起来了。很多同学看到“阶码”“尾数”就慌其实浮点运算的课后题套路比整数乘除法还固定。6.1 典型题浮点加减法五步走看一道题设浮点数格式为 3 位阶码、4 位尾数求[ x2^{011} \times 0.1001, \quad y2^{001} \times 0.1011 ]的和。第一步对阶。阶码差为 (011 - 001 2)按照“小阶向大阶看齐”的规则把阶码较小的 (y) 的尾数右移 2 位[ 0.1011 \rightarrow 0.001011 ]第二步尾数求和[ 0.1001 0.001011 0.101111 ]第三步规格化。看最高有效位是不是 1这里0.101111最高有效位已经是 1不需要左规格化。第四步舍入。如果尾数只保留 4 位0.101111需要处理多出来的低位。按就近舍入可以约成0.1100按截断则保留0.1011。不同教材默认舍入方式不同做题时要看清题干的约定。第五步判溢出。阶码没有超过 3 位能表示的范围结果可表示。最终结果约为[ 2^{011} \times 0.101111 ]我实际验算过(x) 是 (8 \times 0.5625 4.5)(y) 是 (2 \times 0.6875 1.375)两者相加为 5.875也就是 (8 \times 0.734375)和上面算出来的尾数一致。6.2 浮点乘除法只看阶码和尾数浮点乘除法运算相对简单阶码相加或相减尾数相乘或相除最后规格化和舍入。乘法里要注意阶码如果用的是移码相加之后要减掉一个偏置常数。很多教材用的偏置是 (2^{n-1})题目如果没明确说按默认偏置算就行。尾数相乘的符号位处理规则和整数乘法一致同号得正、异号得负。6.3 最容易丢分的阶码溢出问题浮点数的溢出不是看尾数而是看阶码。尾数最高位进位并不代表真溢出因为可以通过右规格化把尾数放回去同时让阶码加 1。真正危险的是阶码自己超过上限。课后题里常出现这种情况尾数相加后是1.1011你以为是溢出其实只要把结果右移一位变成0.11011阶码加 1就重新变成规格化数。阶码如果已经到最大值再加 1 就是上溢这时候计算机才会报“溢出”。所以做题写“溢出”两个字前先问自己是尾数溢出可以修还是阶码溢出没法修前者是正常现象后者才是真错误。7. 这份解析之外的几条实战建议题目做对了不代表这章就学会了。我见过很多学生课后题答案背得很熟但换一组数据就懵问题就出在只记住了“这一题的步骤”没有记住“这一类题的结构”。7.1 把答案升级成“推导过程”做错题之后不要只在旁边改个数字哪怕只是标注一句“因为符号位进位和数值最高位进位不同所以溢出”都会让下次刷题顺畅很多。真正有价值的笔记不是把正确答案抄一遍而是把踩坑点写清楚。7.2 用一张数据通路图串起整章学完这章后可以自己画一遍 16 位 ALU 的数据通路寄存器 A、寄存器 B、ALU、移位器、乘商寄存器、结果总线。每画一次加减乘除的硬件流程会清晰很多。7.3 和笔记、期末卷配合使用的姿势很多人会找王道计算机组成原理笔记或者期末试卷来刷。我的建议是课后题用来打基础笔记用来查漏补缺期末卷用来卡时间训练。不要一上来就做名校期末卷第三章的概念还没理顺时做综合卷很容易被浮点题劝退。最后提一个我试验过很多次的小技巧每次刷完第三章把每类题里的数字换掉重新做一遍。上午做加法、下午做乘法隔一天再全做一次。运算方法这章特别适合“间隔重复”因为它的计算步骤多但题型极其固定只要形成肌肉记忆期末基本不会失分。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →