try ai
科普
编辑
分享
反馈
  • 有符号数乘法

有符号数乘法

SciencePedia玻尔百科
核心要点
  • 标准乘法器对有符号数无效,因为它们没有考虑补码表示中符号位的负权重。
  • Booth 算法通过扫描乘数中的 '1' 和 '0' 字符串来提高效率,用少量的有针对性的加法和减法代替多次加法。
  • Baugh-Wooley 算法通过重构问题,使所有中间部分积都为正数,从而实现了快速的并行硬件。
  • 在数字信号处理 (DSP) 中,有符号数乘法是定点运算的核心,它需要饱和逻辑和位移操作来处理小数值。

引言

乘法是算术的四大基本支柱之一,然而它在数字计算机中的实现却是一项工程智慧的奇迹。虽然正整数的乘法很简单,但负数的引入增加了一层复杂性,很容易让简单的硬件设计出错。核心问题在于计算机如何表示有符号值,通常使用补码系统,这给标准的乘法逻辑带来了独特的挑战。本文将直面这一挑战,揭开有符号数乘法的神秘面纱。

我们的旅程始于第一章“原理与机制”,在这一章中,我们将揭示为什么一个简单的无符号乘法器在处理有符号数时会产生错误结果。然后,我们将深入探讨一些开创性解决方案的精妙逻辑,包括 Booth 算法的顺序执行效率和 Baugh-Wooley 方法的并行处理能力。接下来,“应用与跨学科联系”一章将连接理论与实践。我们将看到这些算法如何在硅片中物理实现,它们如何构成数字信号处理 (DSP) 中定点运算的引擎,以及它们如何在数字通信等领域实现关键功能。读完本文,您不仅将理解有符号数乘法的机制,还将认识到它在驱动我们现代数字世界中不可或缺的作用。

原理与机制

既然我们已经做好了铺垫,现在就让我们卷起袖子,深入计算机的引擎室。一台机器,一个纯粹由逻辑和电流构成的造物,是如何在乘法中处理正数和负数的细微差别的?你可能会想,只要拿一个标准的乘法电路,就是那种为正数构建的电路,它应该就能工作。那么,让我们来做一个小小的思想实验,看看会发生什么。

符号位的欺骗性

−1-1−1 乘以 −1-1−1 是多少?任何一个学童都会告诉你答案是 111。计算机也应该知道这一点,对吧?在 4 位数的世界里,我们使用补码系统将 −1-1−1 表示为 1111。让我们把两个这样的数输入到一个为无符号数设计的简单乘法器中,看看它会输出什么。

无符号乘法器不知道负号。对它来说,1111 不是 −1-1−1;而是数字 8+4+2+1=158 + 4 + 2 + 1 = 158+4+2+1=15。所以,我们这台简单的机器勤奋地计算 15×15=22515 \times 15 = 22515×15=225。在 8 位二进制中,这是 11100001。如果我们尝试将这个结果解释为有符号数,它肯定不是我们期望的 +1+1+1 (即 00000001)。事实上,它表示的是 −31-31−31!我们想要的是 111,得到的却是 −31-31−31。出大问题了。

这个简单的例子揭示了,问题的核心在于一种深刻的解释差异。在一个无符号数中,每一位都代表一个正的位值(20,21,22,…2^0, 2^1, 2^2, \dots20,21,22,…)。但在补码系统中,最高有效位(符号位)带有一个​​负​​权重。对于我们的 4 位数 1111,其值不是 8+4+2+18+4+2+18+4+2+1,而是 −8+4+2+1=−1-8+4+2+1 = -1−8+4+2+1=−1。无符号乘法器完全不了解这一约定,将开头的 '1' 视为一个大的正值 (+23+2^3+23) 而不是一个负值 (−23-2^3−23),从而导致了完全错误的答案。正是这个根本性的冲突,解释了为什么我们需要专门的算法来进行有符号数乘法。这与乘法本身无关,而在于尊重符号位的含义。

乘法的“串”理论:Booth 算法

对这个难题的第一个真正优雅的解决方案来自一位名叫 Andrew Donald Booth 的英国物理学家。他的算法是转换视角的一项杰作。Booth 算法不是将一个数看作是各个位的总和,而是从 '1' 和 '0' 组成的串的角度来看待它。

想一想数字 15,它的二进制是 01111。一个数 MMM 乘以 15 的简单方法是将 MMM 自身相加 15 次,或者更聪明一点,计算 (8×M)+(4×M)+(2×M)+(1×M)(8 \times M) + (4 \times M) + (2 \times M) + (1 \times M)(8×M)+(4×M)+(2×M)+(1×M)。但我们从基础代数中也知道,15=16−115 = 16 - 115=16−1。因此,乘以 15 就等同于乘以 16(在二进制中是一次简单的左移)然后减去一次 MMM。一次移位和一次减法,而不是三次加法和移位。这真是太划算了!

这就是 Booth 算法的核心思想。它对乘数进行重编码,以利用这些捷径。一个 '1' 串,例如 01110 中的 111,被视为在串的开头进行一次减法,在串的末尾进行一次加法。在我们的例子中,01110 被视为 10000 - 00010。因此,我们执行一次减法和一次加法,而不是三次加法。

这种效率在某些情况下尤为显著。考虑找出一个使用 Booth 算法所需操作最少的 4 位数。答案是 1111,即 −1-1−1。一个简单的乘法器会把这看作(暂时忽略符号)乘以 MMM 1+2+4 次,需要多次加法。但 Booth 算法将 1111 视为一个连续的串。它将其重编码为 (10000−1)(10000 - 1)(10000−1),这意味着它在过程的一开始只执行一次减法,此外别无他操作。这是可能的最有效率的情况!我们甚至可以反向操作:+1, 0, 0, 0, -1 的 Booth 重编码意味着我们在开头有一次减法,在五位之后有一次加法,这必定来自于数字 01111 (16 - 1)。

那么,算法是如何自动发现这些串的呢?它用了一个非常简单的技巧:它从右到左扫描乘数的位,成对地查看它们。它检查当前位 (Q0Q_0Q0​) 和刚刚移出的位 (Q−1Q_{-1}Q−1​)。规则很简单:

  • ​​01​​: 我们刚到达一个 '1' 串的末尾。这对应我们 $16-1$ 技巧中的 +1 部分。所以,我们​​加​​上被乘数 (MMM)。
  • ​​10​​: 我们刚到达一个 '1' 串的开头。这是 -1 部分。所以,我们​​减​​去被乘数 (MMM)。
  • ​​00 或 11​​: 我们正处于一个 '0' 串或 '1' 串的中间。不需要改变。我们​​什么都不做​​,只进行移位。

这意味着乘法器硬件的核心在每一步中只需做出三选一的决策:加 MMM、减 MMM(通过加上其补码),或加零。让我们通过将 −5-5−5 乘以 −3-3−3 来看看这个过程。在 4 位表示中,即 M=1011M=1011M=1011 和 Q=1101Q=1101Q=1101。算法一步步进行,移位并应用规则,经过四个周期后,正确的 8 位答案 00001111 (即 +15+15+15) 神奇地出现在寄存器中。这是一场驯服了棘手符号位的、由加法、减法和移位组成的有序、系统性的舞蹈。

构建正数之墙:Baugh-Wooley 方法

Booth 算法优雅且是顺序执行的。但在高性能计算的世界里,“顺序执行”往往是“慢”的代名词。如果我们能并行执行所有必要的工作呢?这需要一种完全不同的理念,由 Charles Baugh 和 Bruce Wooley 首创。

Baugh-Wooley 算法直面符号位问题。当你将两个有符号数 AAA 和 BBB 相乘时,产生的部分积包含正项和负项的混合,这对于在并行硬件中相加来说是一场噩梦。Baugh-Wooley 的天才之处在于它提供了一种方法,能将所有部分积转换为正值,然后将这些正值送入一个快速的并行加法器,如 Wallace tree。

它是如何实现这种魔力的呢?它使用了与补码算术相同的逻辑。为了表示一个负数,比如 −X-X−X,我们可以使用它的补码,计算方法为 (NOT X)+1(\text{NOT } X) + 1(NOT X)+1。Baugh-Wooley 将这个思想应用于由符号位产生的部分积。乘法中本应为负的部分,转而使用部分积的按位取反来计算。这将其转换为正数项。然后,所有这些转换中恼人的 +1 与其他校正因子捆绑在一起,形成一个单一的常数值,加到最终的总和中。

其结果是一个结构优美的位网格,其中所有的位都为正。例如,要计算 A=1011A=1011A=1011 (−5-5−5) 乘以 B=1101B=1101B=1101 (−3-3−3),该算法会生成一个位矩阵。大多数是简单的与门操作 (ai×bja_i \times b_jai​×bj​),但涉及符号位的那些位是反转的。一些固定的 '1' 被散布在特定位置以处理校正。硬件可以同时对这个完整的位矩阵求和,从而产生一个大的数。

该方法的精妙之处在于,这个特殊构建的位矩阵产生的总和​​就是​​最终正确的 2n 位补码乘积。它将一个复杂的有符号问题转化为一个巨大的无符号求和问题,该问题非常适合并行硬件,并直接产生正确的有符号答案。这是一招令人叹为观止的数学柔术:一个将复杂的有符号问题转化为简单的无符号求和问题,从而能够通过大规模并行计算高效解决的算法。

换挡提速:高基数乘法

旅程并未就此结束。Booth 算法的原始形式(称为 Radix-2 或基-2)每个周期处理乘数的一位。工程师们为了追求速度,自然会问:“为什么不同时处理两位呢?”

这就是 ​​Radix-4 Booth 算法​​(基-4 Booth 算法)背后的思想。通过检查乘数位的重叠三位组,该算法可以在每一步处理两位,从而使乘法所需的时间几乎减半。

当然,天下没有免费的午餐。这种额外的速度是以增加复杂性为代价的。简单的操作集 {+M,−M,0}\{+M, -M, 0\}{+M,−M,0} 已不再足够。为了处理所有可能的两位组合,硬件现在还必须能够生成和选择 ±2M\pm 2M±2M。幸运的是,在二进制中从 MMM 生成 2M2M2M 非常简单——只需一次单位左移。因此,硬件变得稍微复杂一些,需要做五选一而不是三选一的决策,但速度的提升通常是值得的。

这一原则构成了一个性能阶梯。一个 Radix-8 (基-8) 算法可以一次处理三位,但需要生成像 ±3M\pm 3M±3M 和 ±4M\pm 4M±4M 这样的倍数,这要求更复杂的电路。在这里,我们看到了工程设计中的一个基本权衡:对速度的不懈追求与硬件复杂性限制之间的平衡。从最初意识到符号位很棘手,到 Booth 优雅的基于串的方法,再到 Baugh-Wooley 的大规模并行,以及高速的基数方法,有符号数乘法的故事完美地诠释了驱动我们数字世界运转所需的创造力。

应用与跨学科联系

在窥探了有符号数乘法的巧妙机制之后,我们可能会倾向于认为这是一个已经解决的问题,一个尘埃落定的算术机器部件。但这就像研究了活塞的设计就以为自己理解了整个交通运输世界一样。真正的魔力,真正的美,不仅在于这些乘法器如何工作,更在于它们成就了什么。我们讨论的这些原理并非抽象的好奇心;它们是现代技术的心跳。让我们踏上一段旅程,从这些运算诞生的硅片,到它们所驱动的宏伟系统。

机器之心:在硅片上打造乘法器

我们知识最直接的应用是在数字硬件本身的设计中。当工程师着手构建一个新的处理器时,他们不是焊接单个的门电路;他们是在像 VHDL 或 Verilog 这样的硬件描述语言 (HDL) 中编写电路行为的描述。在这里,我们抽象的理解变成了具体的代码。一个看似简单的任务,如将电压乘以电流来计算瞬时功率,也需要仔细处理。原始输入,通常表示为通用的 [std_logic](/sciencepedia/feynman/keyword/std_logic)_vector,必须在执行乘法之前被显式地解释为有符号数。然后,编译器将这个描述合成为一个逻辑门网络,这是我们所学到的有符号数乘法规则的物理体现。

但仅仅得到正确答案是不够的;我们还需要它快。这就是我们研究过的那些优雅算法大显身手的地方。以 Booth 算法为例。它不是为乘数中的每一个 1 都机械地加上被乘数,而是智能地跳过长串相同的位,用几次加减法代替多次简单的加法。为了实现这一点,工程师们设计了一个控制器,一个微小的数字大脑,通常被概念化为算法状态机 (ASM)。这个控制器精确地指导数据通路,按精确的顺序发出“加”、“减”或“移位”等命令来执行算法的逻辑。更进一步,Radix-4 Booth 重编码检查乘数的重叠位组,进一步减少需要生成的部分积数量,这对高性能处理器来说是一项关键的优化。

一旦这些部分积生成,我们便面临着将它们相加的挑战。一个简单的顺序加法器将是一个可怕的瓶颈。这就是 Baugh-Wooley 算法展现其天才之处的地方。它巧妙地重构了补码数的乘法,使得所有中间部分积位都为正。这是一个深刻的转变,因为它使我们能够释放并行加法的全部威力。然后,求和任务通常被交给一个 Wallace Tree,这是一种像并行锦标赛一样运作的优美结构。它不是在一个长链中一次加两个数,而是将一列中的每三位分为一组,用一个全加器对它们求和,然后将和位向下传递,将进位位横向传递。在一系列并行的级联中,一个高高的部分积堆栈被迅速压缩成仅两个数,然后可以用一个最终的快速加法器将它们相加。这些算法的相互作用——用 Booth 算法减少乘积项,用 Baugh-Wooley 算法简化它们,用 Wallace tree 对它们求和——是硬件层面优化的一首交响曲。

连接数字与模拟世界:定点运算与 DSP

当然,真实世界不是由整数构成的。它是一个由连续的模拟量组成的世界。为了在数字计算机上处理这些量,我们必须对它们进行近似。虽然浮点数提供了很大的范围和精度,但所需的硬件复杂且耗电。在嵌入式系统和数字信号处理 (DSP) 中,一种更常见的方法是定点运算。

在这种方案中,我们将数字视为整数,但我们维护一个隐含的二进制小数点。一个标准的有符号整数乘法器成为这种运算的核心引擎。如果我们乘以两个 Q7.9 格式的数(一种有 7 个整数位和 9 个小数位的格式),整数乘法器会给我们一个 32 位的结果。然而,真实的结果是一个 Q14.18 格式的数;二进制小数点已经移动了。为了使我们的结果回到原始格式,我们必须执行一次算术右移,实际上是通过除以 2 的幂来重新对齐二进制小数点,并从完整乘积中选择正确的位片段。这个简单的移位操作将整数硬件的世界与分数数学的世界连接起来。

但如果我们的乘积太大,无法容纳在可用的位数中,会发生什么?一个整数会简单地“回绕”,将一个大的正数变成一个大的负数——如果这个数代表像素的亮度或声音的音量,那将是一场灾难。为了防止这种情况,DSP 工程师采用*饱和运算*。逻辑简单但至关重要:如果结果超过了可表示的最大值,我们将其“钳位”在该最大值。如果低于最小值,我们将其钳位在最小值。这个在硬件中易于实现的优雅修复,防止了刺耳的音频爆音和奇异的视觉失真,确保我们的数字体验保持平滑和可预测。

在许多 DSP 应用中,例如数字滤波器,我们经常将信号乘以一组常数系数。在这里,构建一个功能齐全的乘法器就有些小题大做了。对于像 C=−2.5C = -2.5C=−2.5 这样的常数,我们可以将其分解为 2 的幂:C=−(2+0.5)C = -(2 + 0.5)C=−(2+0.5)。然后,将一个数 XXX 乘以 CCC 就变成了 Y=−(2X+0.5X)Y = -(2X + 0.5X)Y=−(2X+0.5X)。在二进制中,这非常高效:它只是一次左移、一次右移、一次加法和一次取反——这些操作在硅片中比通用乘法快得多,也便宜得多。

这些实用技巧有其深刻的理论基础。定点格式的选择(Qm.nQm.nQm.n 中 mmm 和 nnn 的值)是动态范围和精度之间的一个基本工程权衡。每一次乘法都会使小数位数加倍,导致必须管理的位增长。将完整乘积舍入回目标精度的过程会引入一个小的、不可避免的误差。严谨的分析表明,通过精心设计的“四舍五入到最近偶数”方案,这种量化误差可以被严格限制,通常限制在最小可表示步长的一半以内,从而确保整个系统的数值稳定性。

运行中的乘法器:驱动算法与系统

有了这些强大而高效的乘法器,我们就可以构建真正卓越的系统。在数字信号处理中,最基本的操作之一是卷积,它被用于滤波、回声效果和图像处理。在其核心,卷积是大量的乘法和加法。对于长信号和长滤波器,直接计算可能会慢得令人望而却步。在这里,我们看到了一个算法独创性的优美例子。通过对信号和滤波器进行快速傅里叶变换 (FFT),我们从时域转换到频域。卷积定理告诉我们,时域中繁重的卷积过程在频域中变成简单的逐元素相乘。在这次乘法之后,我们使用逆 FFT 返回到时域。通过用几次 FFT 和一组复数乘法来换取大量的简单乘法,我们可以为长信号实现显著的加速。

乘法在通信中的作用同样至关重要。你的收音机是如何调到特定电台的?答案是混频,它就是乘法。当一个包含数千个电台的接收无线电信号,与一个来自本地振荡器的纯余弦波相乘时,输入信号中的每个频率都会被向上和向下平移。通过将结果通过一个低通滤波器,我们就可以分离出那个新的、平移后的频率降至零的电台,从而有效地选择该频道。这个原理被称为外差,是无线电接收的基石。

当事情稍有差错时,这个过程的优雅之处就显露无疑。在单边带 (SSB) 信号的相干解调器中,接收器必须将输入信号与一个本地生成的、完全同步的载波相乘。如果存在一个小的恒定相位误差 ϕ\phiϕ 会怎样?数学表明,输出不再是纯粹的消息信号 m(t)m(t)m(t)。相反,它变成了 m(t)cos⁡ϕ+m^(t)sin⁡ϕm(t)\cos\phi + \hat{m}(t)\sin\phim(t)cosϕ+m^(t)sinϕ,其中 m^(t)\hat{m}(t)m^(t) 是消息的希尔伯特变换。期望的信号被一个因子 cos⁡ϕ\cos\phicosϕ 衰减,更糟糕的是,一个与 sin⁡ϕ\sin\phisinϕ 成正比的“串扰”分量从正交通道泄漏进来,导致失真。这一个应用就展示了乘法作为频率转换工具的作用,并同时揭示了复杂系统对这一基本操作精确执行的深刻敏感性。

从 Wallace tree 中电子的复杂舞蹈,到全球通信网络中信号的宏伟交响,小小的有符号数乘法是一位无名英雄。它是一座连接抽象数学和物理现实的桥梁,一个基本的原语,通过层层工程天才和算法的精妙设计,使我们的数字世界成为可能。