try ai
科普
编辑
分享
反馈
  • 无符号数减法

无符号数减法

SciencePedia玻尔百科
核心要点
  • 数字电路并非直接执行减法,而是通过使用减数的2的补码将问题转化为加法。
  • 通过在一个输入端使用可控反相器(异或门)并控制加法器的初始进位输入位,可以高效地构建一个单一的加法器/减法器电路。
  • 减法操作产生的最终进位输出位提供了一个免费的比较工具,用以指示被减数是否大于或等于减数。
  • 整个方法由模运算的原理统一起来,这解释了为何同一硬件能正确处理无符号数和有符号数的操作。

引言

构建于简单加法逻辑之上的计算机是如何处理减法的?虽然可以设计一个专用的“减法器”电路,但存在一种远为精妙和高效的解决方案——一种复用现有加法硬件的方案。这就引出了一个根本性问题:一个操作如何能被转化为其相反的操作?本文将揭开无符号数减法的神秘面纱,展示支撑数字计算的数学之美。在接下来的章节中,我们将首先深入探讨​​原理与机制​​,探索将减法变为加法的2的补码方法,并审视实现这一功能的巧妙硬件设计。随后,我们将在​​应用与跨学科联系​​中拓宽视野,发现这一基础运算如何支持从编程中的逻辑比较到数字信号处理等领域的高级功能。

原理与机制

想象一下教一台机器做减法。当然,你可以构建一个专用的硬件,一个“减法器”,将其所有复杂的借位规则硬连接到逻辑门中。但自然界——以及优秀的工程设计——往往出人意料地经济。它倾向于复用和改造。如果我们能教会一个现有的、已经懂得如何加法的电路来执行减法,会怎么样?这不仅仅是一个聪明的技巧,更是一扇通往支撑所有数字计算的美丽、统一的数学世界的窗口。

传统方法:向邻位借位

让我们从已知的知识开始。当你手算减法时,你是逐列从右到左进行的。如果你需要从一个较小的数字中减去一个较大的数字(比如 3−73 - 73−7),你会从左边的列“借位”。完全相同的原理也适用于二进制数。唯一的区别是你处理的是0和1。

考虑从 M=110101102M = 11010110_2M=110101102​ 中减去 S=011011012S = 01101101_2S=011011012​。我们将它们对齐,然后像小学时一样,从右到左,逐位进行。

loading

最右边一位是 0−10 - 10−1。我们无法计算,所以从左边一位借位。在十进制中,借位得到10。在二进制中,借位得到2。所以第一位变成 (0+2)−1=1(0+2) - 1 = 1(0+2)−1=1。我们借位的那一位,原本是1,现在变成了0。这个过程继续下去,每当需要时,“借位”就会向左涟漪般传播。最终的结果,你可以验证,是 01101001201101001_2011010012​。这很直接,但在电路中构建这种借位逻辑比看起来要复杂。

借无可借:借位输出信号

那么,如果我们试图从一个较小的数中减去一个较大的数,会发生什么呢?让我们想象一个简单的无人机高度计,它将旧高度存储在寄存器A中,为100121001_210012​(9米),新高度存储在寄存器B中,为011020110_201102​(6米)。为了计算变化量,无人机的计算机会计算B - A,即01102−100120110_2 - 1001_201102​−10012​。

如果我们尝试使用借位法,我们会在最左边一位立即遇到问题。在所有借位完成后,我们发现需要从一个不存在的左侧列借位。这就像一张空头支票!机器通过设置一个特殊的额外位,称为​​借位输出​​(borrow-out)位,并将其置为1来发出此事件的信号。对于我们的无人机,4位结果将是 110121101_211012​,借位输出为1。

这个4位的结果 110121101_211012​ 看起来不像-3。而那个借位输出位像是一个错误标志。对于无符号数,它只是告诉我们已经超出了正数的范围。这是一条至关重要的信息:它意味着 AAA 大于 BBB。但这感觉我们走到了死胡同。要更进一步,我们需要一个新的视角。

天才之举:将减法转化为加法

真正的魔法从这里开始。让我们暂时完全忘记减法。我们计算机所拥有的只是一个​​加法器​​。我们如何用它来计算 A−BA - BA−B?关键的洞见是找到一个作用类似于−B-B−B的数。在数学中,我们称之为加法逆元。如果我们能找到 −B-B−B 的二进制表示,那么我们就可以简单地使用加法器计算 A+(−B)A + (-B)A+(−B)。

这个神奇的表示法被称为​​2的补码​​。找到一个NNN位数BBB的2的补码的规则很简单:

  1. 翻转BBB的每一位。(这被称为​​1的补码​​,记作 Bˉ\bar{B}Bˉ)。
  2. 将结果加1。

所以,操作 A−BA - BA−B 变成了 A+Bˉ+1A + \bar{B} + 1A+Bˉ+1。这看起来很有希望!我们有一个加法,还有一个加1的操作。加法器电路可以完美地处理这个。

让我们用前面的例子来测试一下,M=11012M = 1101_2M=11012​ 和 S=01102S = 0110_2S=01102​。我们想计算 13−613 - 613−6。

  1. 减数是 S=01102S = 0110_2S=01102​。
  2. 通过翻转各位来求其1的补码:Sˉ=10012\bar{S} = 1001_2Sˉ=10012​。
  3. 加1得到2的补码:10012+1=101021001_2 + 1 = 1010_210012​+1=10102​。
  4. 现在,将被减数与它相加:M+(S的2的补码)=11012+10102M + (\text{S的2的补码}) = 1101_2 + 1010_2M+(S的2的补码)=11012​+10102​。

让我们进行加法运算:

loading

结果是5位长,但我们是在一个4位系统中工作。我们只需丢弃最后的进位输出位(最左边的'1')。结果是 011120111_201112​,即十进制的7。完美成功!

技巧的核心:硬件如何实现

这个过程不仅仅是一个数学上的奇思妙想;它直接映射到一个极其精妙的硬件设计。一个加法器/减法器单元使用一个标准的N位加法器,但在其中一个输入端放置了一排可控反相器(异或门)。

  • 一个控制信号,我们称之为SUB,来管理操作。
  • 如果SUB = 0(用于加法),异或门会直接让BBB的各位通过,不做改变,并且加法器的初始进位输入为0。电路计算 A+B+0A + B + 0A+B+0。
  • 如果SUB = 1(用于减法),异或门会翻转BBB的每一位(产生Bˉ\bar{B}Bˉ),并且SUB信号也被馈送到加法器的初始进位输入,使其为1。电路现在计算 A+Bˉ+1A + \bar{B} + 1A+Bˉ+1。

这就是它的美妙之处。完成2的补码所需的“+1”并不是一个独立的步骤;它是由加法器自身的初始进位输入“免费”提供的。如果那个进位输入有故障并卡在0呢?电路将计算 A+BˉA + \bar{B}A+Bˉ,数学上这等于 A−B−1A - B - 1A−B−1。结果会恰好差一,这正好说明了那个微小的初始进位输入位是多么重要。每个部分都有其不可或缺的位置。

进位位的秘密:一个免费的比较工具

我们看到,当我们用传统方式做减法时,“借位输出”会告诉我们是否正在从一个较小的数中减去一个较大的数。现在,使用我们基于加法器的方法,我们从加法的最后阶段得到了一个“进位输出”位。这个位能告诉我们什么有用的信息吗?

令人惊讶的是,它告诉我们的完全是同一件事,只是反了过来!

  • 如果 Cout=1C_{out} = 1Cout​=1,意味着 A≥BA \ge BA≥B。
  • 如果 Cout=0C_{out} = 0Cout​=0,意味着 A<BA \lt BA<B。

这不是巧合。这是我们方法的直接数学结果。记住,加法器正在计算值 T=A+Bˉ+1T = A + \bar{B} + 1T=A+Bˉ+1。对于一个NNN位系统,1的补码 Bˉ\bar{B}Bˉ 在数学上等价于 (2N−1)−B(2^N - 1) - B(2N−1)−B。所以总和是:

T=A+((2N−1)−B)+1=A−B+2NT = A + ((2^N - 1) - B) + 1 = A - B + 2^NT=A+((2N−1)−B)+1=A−B+2N

现在,想一想一个NNN位加法器做了什么。它产生一个NNN位的结果和一个单独的进位输出。这就像除法一样。NNN位的结果是你用TTT除以2N2^N2N的余数,而进位输出是商。

  • 如果 A≥BA \ge BA≥B,那么 A−B≥0A - B \ge 0A−B≥0。总和 T=(A−B)+2NT = (A - B) + 2^NT=(A−B)+2N 将大于或等于 2N2^N2N。当我们除以 2N2^N2N 时,商必须是1。所以,Cout=1C_{out} = 1Cout​=1。
  • 如果 A<BA \lt BA<B,那么 A−BA - BA−B 是负数。总和 T=(A−B)+2NT = (A - B) + 2^NT=(A−B)+2N 将小于 2N2^N2N。当我们除以 2N2^N2N 时,商必须是0。所以,Cout=0C_{out} = 0Cout​=0。

所以,我们减法器电路的进位输出位实际上是一个内置的比较器!通过简单地检查这一位,机器可以立即知道 A≥BA \ge BA≥B 还是 A<BA \lt BA<B。例如,在计算 10012−110021001_2 - 1100_210012​−11002​ (即 9−129 - 129−12)时,电路正确地产生一个最终进位输出 C4=0C_4 = 0C4​=0,表明结果是负的。

统一原理:模运算之美

我们现在来到了整个故事中最深刻、最美丽的部分。同一个加法器/减法器电路,既能为无符号数(如高度或计数)计算 A−BA - BA−B,也能为有符号数(如温度或银行余额)的减法给出正确的位模式(使用2的补码表示负值)。为什么?一个电路怎么能处理两种看起来不同的数字系统?

答案是,在硬件层面,只存在​​一个​​系统:圆环的算术。想象一下一台8位计算机上的数字,不是从0到255的一条线,而是像钟表上的数字一样,排列在一个圆上的256个点。当你相加超过255时,你不会产生错误;你只是“环绕”回到0。这就是​​模运算​​,所有计算机加法器从根本上都是模2N2^N2N的机器。

2的补码表示法不仅仅是一个随意的技巧;它是一种独特的映射,使得负数——加法逆元的概念——在这个模世界中完美地工作。BBB的2的补码是那个必须与BBB相加才能在圆环上回到0的数。

所以,当硬件计算 A+Bˉ+1A + \bar{B} + 1A+Bˉ+1 时,它只是在这个模2N2^N2N系统中找到了 A−BA - BA−B 的结果。它不知道你,程序员,是把位模式 111111111111111111111111 看作无符号数255还是有符号数-1。它只是进行数学运算。最终得到的位模式对于两种解释都是正确答案(前提是你没有离开圆环,即没有溢出),这一事实证明了该系统深刻的数学统一性。看起来像是两个不同的工作——无符号数减法和有符号数减法——从硬件的角度来看,是完全相同的任务,由一个精妙的机制解决。

应用与跨学科联系

既然我们已经深入了解了二进制减法的内部机制,你可能会有一个非常合理的问题:“那又怎样?”我们已经看到,减法实际上只是一种巧妙的加法形式,一个利用反相器和进位输入位的小技巧。但真正的魔法从这里开始。这个单一、精妙的技巧不仅仅是一个计算上的捷径;它是构建起现代技术这座宏伟复杂大教堂的基石。通过理解减法,我们不仅仅理解了一种算术运算;我们获得了一把万能钥匙,可以打开驱动从最简单的计算器到最复杂的数字信号处理器的逻辑之门。

减法器:伪装的加法器

让我们从最直接的应用开始。计算机的算术逻辑单元(ALU)——其计算核心——实际上是如何执行减法的?当加法和减法如此密切相关时,为它们构建完全独立的电路是低效的。相反,工程师们利用了我们已经探讨过的原理:要计算 A−BA-BA−B,机器只需计算 A+B‾+1A + \overline{B} + 1A+B+1。一个标准的加法器电路只需极少的改动就可以转变为一个专用的减法器。所需要的只是一组非门(NOT gates)来翻转减数 BBB 的各位,以及一个固定的'1'馈入加法器的初始进位输入线。这是工程优雅的典范——以一个(外加几个反相器)的代价创造了两个功能。这个原理是ALU的基石,ALU通常有一条控制线,决定BBB输入是直接通过(用于加法)还是反相(用于减法)。

超越计算:作为比较工具的减法

也许减法最深刻的应用不是求差,而是做决策。当你执行 A−BA-BA−B 操作时,数值结果只是故事的一半。操作中“剩下”的位——最终的进位输出(或借位)以及检查结果是否为零的标志位——是信息的宝库。

考虑减法器的借位输出位。只有当AAA小于BBB时,它才会变为'1',因为操作需要从一个更高、不存在的位“借位”。如果减法的结果是零,则意味着AAA和BBB是相同的。通过简单地检查这两个信号——借位和零标志位——我们就可以构建一个完整的​​数值比较器​​。一个简单的电路就能回答这个问题:A>BA > BA>B吗?当且仅当没有借位且结果不为零时,答案是“是”。通过这种方式,一个不起眼的减法器成为了逻辑的仲裁者,做出支撑计算机程序中每一个if语句的关键决策。

这种联系的美妙之处甚至更深。当我们设计高速加法器,如超前进位加法器(Carry-Lookahead Adder, CLA)时,我们会创建特殊的内部信号来快速判断进位将在何处产生。这些信号,通常称为“传递”(PPP)和“生成”(GGG),是为了使加法快速而设计的。但事实证明,当CLA被配置为减法器时,这些相同的信号具有双重含义。一个位上的“生成”信号对应于AAA的位大于BBB的位的情况,而“传递”信号则对应于它们相等的情况。通过组合这些内部信号,我们可以在不执行完整减法的情况下构建一个高速比较器!这揭示了数字设计中惊人的统一性:使算术快速的逻辑,从另一个角度看,就是比较本身的逻辑。

从简单模块到复杂功能

一旦我们拥有了这些基本的构建模块——减法和比较——我们就可以开始构建更复杂的算术功能。

例如,在图像处理中,一个常见的任务是找出两个像素之间的亮度差异。这需要计算​​绝对差​​,∣A−B∣|A-B|∣A−B∣。一个电路可以通过执行减法 A−BA-BA−B 并使用进位输出标志作为决策者来完美地实现这一点。如果进位输出是'1'(意味着 A≥BA \ge BA≥B),结果已经是正确的正值。如果进位输出是'0'(意味着 A<BA < BA<B),结果是一个2的补码形式的负数。电路随后使用这个进位标志来有条件地执行第二个操作:对负数结果取2的补码,将其翻转回我们期望的正值。

这种向上构建的主题仍在继续。我们可以设计电路来测试更抽象的数学性质。例如,检查三个数 AAA、BBB 和 CCC 是否构成等差数列,需要验证 B−A=C−BB-A = C-BB−A=C−B。使用两个减法器的天真实现看似显而易见,但对二进制算术的更深理解揭示了一个更稳健的解决方案。通过代数上将方程重新排列为 A+C=2BA+C = 2BA+C=2B,我们可以用一个加法器和一个简单的移位操作(硬件就是这样执行乘以二的)来构建电路。这避免了无符号减法的潜在陷阱,如下溢,其中 0−10-10−1 不会得到 −1-1−1,而是环绕到可能的最大数。这显示了数学洞察力与稳健硬件设计之间的相互作用。

现实世界的约束与计算理论的联系

到目前为止,我们一直想象我们的电路是瞬间运行的。在现实世界中,工程师们面临着速度、成本和物理空间之间的持续权衡。一个同时处理所有8、16或32位的“并行”减法器速度快,但需要大量硬件。另一种选择是​​串行减法器​​,它只使用一个全减器,在几个时钟周期内,一次处理一位,从最低有效位(LSB)开始。每次位计算产生的关键借位输出被存储在一个单位存储元件(一个触发器)中,并作为下一周期的借位输入反馈回来。这种方法慢得多,但它非常紧凑和高效,非常适合空间有限的应用。

令人着迷的是,这个小小的串行电路——一个减法器和一个用于借位的一位存储器——是计算机科学中一个抽象概念的完美物理体现:​​有限状态机(FSM)​​。该机器有一个“状态”(存储的借位),它根据当前输入影响其输出和下一个状态。通过将我们的串行减法器形式化为Moore机,我们弥合了具体数字硬件与抽象计算理论之间的鸿沟。这个简单的设备,本质上是一台执行单一算法的微型专用计算机。

跨学科前沿

无符号减法的原理向外辐射到许多其他领域。

  • ​​数字信号处理(DSP):​​ 在音频或视频处理等应用中,标准的“环绕”溢出是灾难性的。从一个大的负数中减去一个大的正数可能会溢出并环绕到一个大的正数结果,在音频中产生可听见的“爆音”或在图像中产生奇异的像素。为了解决这个问题,DSP使用​​饱和算术​​。溢出时不是环绕,而是将结果“饱和”或“钳位”在系统可以表示的最大正值或最大负值。这需要特殊的逻辑来检测溢出的条件(例如,从一个正数中减去一个负数得到负数结果),然后强制输出到适当的最大值或最小值。

  • ​​检错与纠错码理论:​​ 数字逻辑的世界充满了惊人的联系。异或门(XOR gate),作为减法逻辑的核心(Di=Ai⊕Bi⊕biD_i = A_i \oplus B_i \oplus b_iDi​=Ai​⊕Bi​⊕bi​),也是用于错误检测的奇偶校验计算的核心。可以设计一个系统来计算绝对差 ∣A−B∣|A-B|∣A−B∣ 的奇偶性,不是通过先计算差值再计算其奇偶性,而是通过巧妙地将输入(AAA和BBB)的奇偶性与减法过程中产生的内部借位信号的奇偶性结合起来。这展示了算术运算与数据完整性原理之间深刻而非显而易见的关系。

  • ​​补码的普适性:​​ 最后,值得记住的是,“2的补码技巧”只是一个更普遍数学原理的一个实例。通过加补码来执行减法的思想适用于任何数基。对于十进制,我们有10的补码。对于一个假设的八进制计算机,我们将使用8的补码。其基本原理是普适的。我们的二进制机器使用2的补码仅仅是因为它们是由具有两种状态的开关构建的。

从一个简单的硬件技巧出发,我们穿越了逻辑、决策、高级算术、计算理论,并进入了信号处理和数据完整性的专业领域。不起眼的减法运算,事实证明,一点也不简单。它是工程学层次之美的证明,一个单一、聪明的想法可以在一层又一层的抽象中回响,从而支撑起一个充满复杂奇妙技术的世界。

1 1 0 1 0 1 1 0 (M) - 0 1 1 0 1 1 0 1 (S) -----------------
1101 (M) + 1010 (S的2的补码) ------- 10111