2026/10/12 12:50:14

原码与补码加减交替法定点除法:原理、对比与手算实战

原码与补码加减交替法定点除法:原理、对比与手算实战 定点除法在计算机组成原理里是个经典老大难。课本上原码和补码的加减交替法只差几个字真到自己动手算时符号、移位、余数修正全搅在一起特别容易崩。这篇文章就把这两个方法放到一起用同一组被除数和除数把每一步运算掰开来看再把它们的符号处理、上商规则、修正方式逐项对比清楚。适合正在学计算机组成原理的本科生也适合准备考研或做硬件除法器设计的同学。1. 加减交替法到底在做什么除法器的心法1.1 二进制除法就是“移位加试商”先回到小学的长除法。十进制里我们一位一位地试商比如 8 除以 3先看商的十位再看个位。二进制更简单因为每一位商只有 0 或 1 两种可能试商其实就是判断“当前剩下的这部分够不够减一次除数”。不过处理器不会“看着像就猜”晶体管只能老老实实移位和加减所以硬件除法器被设计成循环结构用当前余数第一次是被除数左移一位相当于把下一位拉下来判断左移后的数能不能减去除数够减就上商 1不够减就上商 0根据上商结果决定加还是减除数进入下一次循环。整个过程写出来就是一个不断“左移—比较—加减—上商”的流水线。加减交替法正是这个流水线的核心实现。1.2 恢复余数法的尴尬与加减交替法的动机最直接的一种实现叫“恢复余数法”。它的逻辑很直白每一步先做余数左移减除数如果结果为负说明这一步其实不够减那就把除数再加回来恢复原来的余数商上 0。问题是一旦出现“不够减”一个周期里就要做两次加法或减法先减一次再加一次白白浪费一个时钟周期。除法本身就要循环几十次每次多一拍性能损失非常可观。加减交替法也叫不恢复余数法的思路是既然这次不够减那就不恢复让余数先“欠着”负数照样留下下一步再把除数加回来。用生活里的话说恢复余数法像“付了款发现不够又退款重来”加减交替法像“先记账下次合并结算”。这个“欠账”并不影响商的正确性因为二进制小数的每一位商由余数的正负决定而负数余数在下一次左移后参与运算正好会把上次多减的部分补回来。数学上看如果某一步算出余数 r 为负下一步本来应该先恢复成 rY再左移得 2(rY)然后减 Y。而加减交替法直接左移再补偿本质是利用了 2(rY)-Y 2rY 这个等式把两步合并成一步操作。这就是它省时间的根本原因。1.3 一个容易被忽略的大前提定点小数除法成立的前提是被除数的绝对值必须小于除数的绝对值。否则商就会大于 1超出定点小数的表示范围。比如 0.1101 除以 0.0011结果约等于 3.9根本装不进只有 1 位整数位的寄存器。所以在进入除法器之前硬件会先做一次溢出判断一旦发现被除数比除数大或相等就置溢出标志中断除法过程。实际操作时也要先确认这一点很多例题错不是错在中间步骤而是一开始商的范围就错了。2. 原码加减交替法规则与逐步例题2.1 原码除法的三条核心规则原码表示的符号和数值是分开的所以原码除法把问题拆成两半商的符号单独计算等于被除数符号与除数符号相异或数值部分完全按两个正数的绝对值来做不掺任何符号每步先把余数左移一位如果上一步商 1 就减去除数上一步商 0 就加上除数然后看结果正负决定当前商位。这套流程执行 n 次得到 n 位小数商。注意第一步比较特殊它没有“上一步”可以参考所以直接做一次左移再减除数相当于默认上一次商的初始值为 1。得到的余数为负就说明首位商应该是 0如果余数非负首位商为 1。2.2 原码除法例题X0.1011Y0.1101取被除数 X0.1011除数 Y0.1101都是正数符号位不用额外处理数值部分各 4 位。用 A 表示余数寄存器B 表示除数B0.1101减 B 等价于加 B 的补码但为了看得直观下面直接写减法结果。过程分 4 步步骤操作内容余数结果商位1A0.1011 左移得 1.0110A-B1.0110-0.11010.1001非负12A0.1001 左移得 1.0010上步商 1做 A-B0.0101非负13A0.0101 左移得 0.1010上步商 1做 A-B-0.0011为负04A-0.0011 左移得 -0.0110上步商 0做 AB0.0111非负1得到的 4 位商是 0.1101也就是 0.8125。最后余数寄存器里是 0.0111但这里要当心整个过程做了 4 次左移相当于把余数放大了 16 倍所以真余数应该是 0.0111 × 2⁻⁴ 0.02734375。验算一下0.1101 × 0.1101 0.66015625加上 0.02734375正好回到 0.6875等于原来的被除数 0.1011。公式 X Y × Q R 成立。2.3 余数为负时为什么要补一步上面这个例子里第 3 步出现了余数 -0.0011这是典型的“不够减”。加减交替法的处理是不恢复余数直接带着负数继续。所以第 4 步先从 -0.0011 左移得到 -0.0110然后因为上一步商 0就把除数加回来-0.01100.11010.0111。最终余数又回到正值。如果全部 n 步走完发现最后一步的余数是负的那就需要做一次修正给余数加一个除数让它恢复为正数这样余数的符号才能与被除数保持一致。这个“最后余数修正”是原码除法最容易漏的一步考试和硬件实现里都值得单独标记。2.4 分步流程为什么必须先左移再加减原码加减交替法的每一步是固定的流水顺序先左移再根据上一步商做加减最后看结果上商。如果反过来先加减再左移得到的中间状态完全不同。可以简单证明一下假设当前余数为 -0.0011正确做法是左移得到 -0.0110再加 B 得 0.0111如果先加 B 得 0.1100再左移得到 1.1000完全不对。所以实际操作中宁肯把流程背成顺口溜“左移、加减、上商”也不要临场自己猜。3. 补码加减交替法符号位参与运算的完整例题3.1 补码除法的设计思想补码的厉害之处在于减法可以统一成加法符号位也直接参与运算。原码除法要单独弄一个异或电路算符号补码除法不需要商的符号在第一次上商时就会自然生成。代价是规则细节更绕而且通常需要双符号位来防止中间结果溢出。双符号位就是把正数写成 00.xxxx负数写成 11.xxxx。00.1011 表示 0.101111.0011 表示 -0.1101 的补码。中间结果如果出现 01.xxxx 或 10.xxxx说明数值超出了 [-1, 1) 的标准范围但只要还在双符号位可表达的 [-2, 2) 之内就仍然是合法中间值可以继续往下算。这一点特别容易吓到初学者。3.2 补码除法的完整口诀补码加减交替法的流程可以浓缩成四句话第一步被除数与除数同号则相减异号则相加以后每一步余数与除数同号上商 1异号上商 0上商之后余数左移一位若刚上的商为 1左移后减除数若刚上的商为 0左移后加除数。总共执行 n1 次上商得到 n1 位商其中第 1 位是符号位后面 n 位是数值位。最后一次上商后不再左移也不再做加减。3.3 补码除法例题X0.1011Y0.1101用和原码例题完全相同的数据。被除数 X0.1011双符号位写成 00.1011除数 Y0.1101双符号位写成 00.1101-Y 的补码是 11.0011。流程如下步骤操作内容余数结果商位1X 与 Y 同号RX-Y00.101111.001111.1110与 Y 异号02R 左移得 11.1100上步商 0RY11.110000.110100.1001与 Y 同号13R 左移得 01.0010上步商 1R-Y01.001011.001100.0101与 Y 同号14R 左移得 00.1010上步商 1R-Y00.101011.001111.1101与 Y 异号05R 左移得 11.1010上步商 0RY11.101000.110100.0111与 Y 同号1商的完整序列是 01101按补码格式读就是 0.1101与原码除法得到的结果完全一致。最终余数寄存器中为 0.0111由于中间总共左移了 4 次真余数同样是 0.0111 × 2⁻⁴等于 0.02734375。3.4 中间出现 01.0010 算不算出错第 3 步出现了 01.0010这个数在标准定点小数表示里是 1.125看着很吓人。其实它完全正常。补码除法在部分步骤中余数左移后可能越过 ±1 的边界但只要没超过 ±2双符号位依然能正确编码。01 和 10 只是提醒“值超出常规小数范围”不代表运算出错。真正需要报错的情况是结果超出双符号位的可表示范围比如出现 001 这样的三符号位扩展还装不下的情况。所以做题时看到 01 或 10先冷静下来继续算不要急着放弃。3.5 如果被除数是负数会有什么不同假设被除数改为 X-0.1011双符号位为 11.0101除数仍是正数 00.1101。第一步因为异号做的是加法11.010100.110100.0010。结果与除数同号所以第一次上商就是 1。这个 1 恰好是商的符号位表示负数。也就是说补码除法天然把符号位“算”出来了你不需要知道 X 和 Y 的符号关系第一次上商是什么符号位就是什么。这也是补码除法在硬件上的最大优势省掉了单独的符号处理线路。4. 一张表看懂两者的核心区别4.1 逐项对比表把原码除法和补码除法放在一起看最核心的差异集中在符号位处理、上商依据、操作对象和修正规则上。对比项原码加减交替法补码加减交替法符号处理符号位单独用异或算出符号位直接参与运算第一次上商自动生成运算对象绝对值的正数形式带符号的补码形式上商依据余数大于等于 0 上商 1小于 0 上商 0余数与除数同号上商 1异号上商 0第一步操作左移后减除数同号相减异号相加商位数量n 位全是数值位n1 位含 1 位符号位双符号位不需要需要用于检测中间溢出最后余数修正余数为负时加除数余数与除数异号时修正目标是让余数与被除数同号商的修正一般不需要末位商为 0 时可考虑末位恒置 1 或加 1 校正4.2 为什么补码除法多且必须多算一位原码除法的符号位和数值位是分开的所以 n 位小数商就只做 n 次上商。补码除法的符号位和数值位同在一个补码串里第一次上商就是符号位因此就算数值位只有 n 位也必须要做 n1 次上商才能凑齐完整的补码商。这个“多一位”不是可选项而是格式本身决定的。上商1时做减法、上商0时做加法这一点两个算法其实是共通的。原码里“余数非负上商 1”等价于“余数与除数正数同号上商 1”原码里除数总是正数所以不会暴露“异号上商 0”这个真实规则。补码除法把除数符号也纳入运算后判断依据必须统一成“余数与除数是否同号”否则除数为负时全体翻车。4.3 两个算法的精度和代价原码除法实现简单、概念直观对多人手算和入门理解很友好缺点是需要单独处理符号硬件上多一步异或。补码除法规则更统一、更利于流水线化代价是需要更宽的寄存器、更复杂的上商判断以及严格的溢出检测。实际处理器内部多采用补码流水线因为符号位全程参与运算反而减少了状态切换。两种方法都能达到同样的结果精度区别在效率与实现成本。5. 初学者最常踩的坑与排查技巧5.1 常见错误速查表学习过程中我见过不少人卡在同样的地方整理成表方便自查错误现象根本原因解决办法原码除法第一步就开始错忘了“第一步默认先减除数”把第一步当成上一步商为 1 的延续中间商位全反补码除法还在看余数正负而不是看余数与除数是否同号除数正负都要注意统一按“同号商 1、异号商 0”寄存器越算越乱先加减再左移流程顺序搞反固定为“上商、左移、再加减”或“左移、加减、上商”只选一套看到 01.0010 以为溢出不认识双符号位的中间合法状态双符号位 01/10 表示超出 ±1 但未超 ±2可以继续最终余数忘了缩小忽略左移 n 次相当于余数乘了 2ⁿ真余数 寄存器余数 × 2⁻ⁿ原码最后余数为负没修正忽略符号一致性最后余数为负时加一次除数补码商少一位不知道要算 n1 位第一次上商是符号位必须保留5.2 用验算公式兜底最靠谱的排查方法不是反复检查每一行二进制运算而是直接用公式 X Y × Q R 做总体验算。注意这里的 R 必须是真余数也就是把寄存器里最后的值按左移次数还原回来的数。我自己做例题时每算完一组数据就会立刻用十进制小数把公式再走一遍十秒就能确认结果是否正确。这个方法对原码和补码都适用几乎能拦下 90% 的粗心错误。5.3 不同教材的表述差异别死记关于补码除法的表述不同教材、不同老师的课时笔记会在细节上有差别。有的把“余数与除数同号上商 1”描述成“余数符号与除数符号相同则商 1”有的把“第一步异号相加”直接画在算法图里。乍一看似乎规则不一样实际上内核完全相同。你只要抓住两条主线一是上商依据永远看“余数和除数的符号关系”二是加减依据永远看“刚上完的商是 1 还是 0”。抓稳这两条无论题目怎么换外衣算法都不会错。我在实际手算和写模拟程序时最大的体会是先把“商 1 就减、商 0 就加”这句对称口诀焊在脑子里再处理符号判断。原码和补码的加减交替法本质上都是那个古老的“左移—试商—补偿”循环只差在有符号还是没符号。先弄懂一道题的完整过程再回头对比这两个算法会比孤立背十遍规则管用得多。