try ai
科普
编辑
分享
反馈
  • 二进制补码减法

二进制补码减法

SciencePedia玻尔百科
核心要点
  • 二进制补码允许计算机通过简单地加上一个数的负数表示来进行减法,从而统一了算术运算。
  • 通过使用异或门作为受控反相器并控制初始进位信号,可以创建一个单一、高效的加法-减法器电路。
  • 由于模运算的特性,相同的硬件对于有符号数和无符号数的解释都能正确计算结果。
  • 处理器通过逻辑上检查操作数和结果的符号来检测减法中的溢出错误,确保计算的可靠性。
  • 该原理可扩展到高速加法器和专门的数字系统,展示了其在计算机工程中的通用性和基础性作用。

引言

所有数字计算的核心在于算术,即简单的加法和减法。虽然加法在硬件中实现相对直接,但减法因其“借位”概念而带来了挑战。这可能需要独立、复杂的电路,从而浪费芯片上宝贵的资源。是否存在一种优雅的方式,让计算机使用其已有的加法硬件来执行减法呢?这个难题正由计算机科学中最基本的概念之一——二进制补码表示法——所解决。

本文深入探讨了二进制补码减法的机制和意义,这一巧妙的方法是所有现代计算机算术的基础。通过两大章节,您将全面理解这一至关重要的主题。“原理与机制”章节将剖析将减法转化为加法的数学技巧,解释它如何通过通用加法-减法器电路在硅片上实现,并探讨溢出和符号扩展等关键概念。随后,“应用与跨学科联系”章节将揭示这一原理不仅是理论上的奇思妙想,更是从处理器ALU、高速计算到错误检测以及与不同数字系统接口等一切事物的实用基石。

原理与机制

在每台计算机的核心,从最简单的袖珍计算器到最强大的超级计算机,都隐藏着一个深刻而优雅的技巧。这是一种如此巧妙的障眼法,它将减法这一困难任务,转变成了机器早已擅长的事情:加法。要理解数字世界,我们必须首先理解这个被称为​​二进制补码减法​​的优美的逻辑炼金术。

神奇的技巧:将减法变为加法

想象一下你正在设计一台计算机。构建一个用于两个二进制数相加的电路相对直接。你可以用简单的逻辑门来构建它,通过级联来处理任意大小的数字。但减法更棘手。它涉及“借位”的概念,这显著地复杂化了硬件设计。如果我们能以某种方式通过计算 A+(某个东西)A + (\text{某个东西})A+(某个东西) 来执行操作 A−BA - BA−B,那岂不是妙哉?

那个“某个东西”当然就是 BBB 的负数。真正的问题是,对于一个只理解0和1的电路来说,“负数”究竟意味着什么?答案在于一个有限的、循环的数字世界——一个你早已熟悉的概念。想想汽车的里程表。如果它有五位数,行驶了99999英里后,它会翻转回00000。它在一个封闭系统中运行,数学家称之为​​模运算​​。计算机做的完全相同。一个 NNN 位系统在模 2N2^N2N 下运行。

在这个循环的世界里,我们可以将一个负数 −B-B−B 定义为与 BBB 相加后能回到零的那个数。在二进制中找到这个加法逆元的过程被称为​​二进制补码​​。方法很简单:

  1. 从你的正数 BBB 开始。
  2. 将所有位取反(将每个0换成1,每个1换成0)。这被称为​​反码​​。
  3. 加1。

让我们看看这个魔法是如何运作的。假设一个5位处理器需要计算 9−149 - 149−14。预期答案是 −5-5−5。 首先,我们用5位二进制表示我们的数字:

  • 9109_{10}910​ 是 01001201001_2010012​。
  • 141014_{10}1410​ 是 01110201110_2011102​。

现在,我们求 141414 的二进制补码:

  1. 将 01110201110_2011102​ 的各位取反,得到其反码:10001210001_2100012​。
  2. 加1:100012+12=10010210001_2 + 1_2 = 10010_2100012​+12​=100102​。

所以,在我们的5位系统中,10010210010_2100102​ 是 −14-14−14 的表示。减法 9−149 - 149−14 现在变成了加法 9+(−14)9 + (-14)9+(−14):

\begin{array}{@{}c@{\,}c@{}c@{}c@{}c@{}c} & & 0 & 1 & 0 & 0 & 1_2 & (+9) \\ & + & 1 & 0 & 0 & 1 & 0_2 & (-14) \\ \hline & & 1 & 1 & 0 & 1 & 1_2 & \\ \end{array}

结果是 11011211011_2110112​。这是 −5-5−5 吗?开头的'1'告诉我们这是一个负数。让我们通过对结果本身取二进制补码来找到它的绝对值:将 11011211011_2110112​ 取反得到 00100200100_2001002​,然后加1得到 00101200101_2001012​。这是 5105_{10}510​。所以,11011211011_2110112​ 确实是机器表示 −5-5−5 的方式。这个技巧完美地奏效了。

如果结果是正数会怎样?让我们在一个4位系统中尝试 13−613 - 613−6。

  • 131013_{10}1310​ 是 110121101_211012​。
  • 6106_{10}610​ 是 011020110_201102​。
  • 666 的二进制补码是 (invert 01102)+1=10012+1=10102(\text{invert } 0110_2) + 1 = 1001_2 + 1 = 1010_2(invert 01102​)+1=10012​+1=10102​。

现在相加:11012+10102=1011121101_2 + 1010_2 = 10111_211012​+10102​=101112​。 等等,我们的结果有五位,但我们是在一个4位系统中!我们该如何处理那个开头的'1'?我们只需丢弃它。在我们循环的、模运算的世界里,这个额外的位——​​传出进位​​——仅仅表示我们已经绕数字圈跑了一整圈。最终的位置才是最重要的。我们的4位结果是 011120111_201112​。那么 011120111_201112​ 的十进制是什么?是 777。魔法再次奏效。同样的过程以无可挑剔的优雅处理了正负结果。这个操作是通用的,即使是减去负数,如 −3−(−6)-3 - (-6)−3−(−6) 的情况,也能正确地变成 −3+6=3-3 + 6 = 3−3+6=3。

通用机器:一个电路统治一切

这个算法无疑是优雅的,但当看到它能多么简单地被铸造成硅片时,才真正揭示出其美妙之处。我们如何构建一个电路,能够根据指令执行加法和减法两种操作呢?

我们从一个标准的N位​​并行加法器​​开始,它由一串全加器电路构成。为了把它变成一个减法器,我们需要实现“取反加一”的步骤。这时,一个虽小但功能强大的逻辑门派上了用场:​​异或 (XOR)​​ 门。一个异或门有一个奇妙的特性:如果你将一个位 BiB_iBi​ 输入到一个端口,一个控制信号(我们称之为 SUBSUBSUB)输入到另一个端口:

  • 如果 SUB=0SUB=0SUB=0,输出就是 BiB_iBi​。
  • 如果 SUB=1SUB=1SUB=1,输出就是 BiB_iBi​ 的反码,即 Bi‾\overline{B_i}Bi​​。

它是一个完美的受控反相器!通过在加法器的B输入路径上放置一个N个异或门的阵列,我们仅需将 SUBSUBSUB 信号从0翻转到1,就可以控制加法器看到的是 BBB 还是其反码 B‾\overline{B}B。

这解决了“取反”部分。但“加一”怎么办呢?解决方案更加优雅。我们的并行加法器在第一个全加器(用于最低有效位)上有一个进位输入端口 CinC_{in}Cin​。对于正常的加法,它被设置为0。如果我们也将我们的 SUBSUBSUB 信号连接到这个进位输入端口呢?

让我们看看会发生什么:

  • ​​当 SUB=0SUB=0SUB=0 (加法模式):​​ 异或门将 BBB 原封不动地通过,初始进位为0。电路计算 S=A+B+0S = A + B + 0S=A+B+0。
  • ​​当 SUB=1SUB=1SUB=1 (减法模式):​​ 异或门输出反码 B‾\overline{B}B。初始进位为1。电路计算 S=A+B‾+1S = A + \overline{B} + 1S=A+B+1。

就是这样!A+B‾+1A + \overline{B} + 1A+B+1 精确地是二进制补码减法的操作。通过一根控制线,我们优雅地指示整个电路将其角色从加法器切换为减法器。完全不需要第二个独立的减法电路。这种资源复用和功能优雅的原则是现代数字设计的基石。

深度统一:有符号、无符号,全都一样?

此时,一个好奇的想法可能会产生。我们一直在讨论有符号数,它们有正负值。但计算机也处理无符号数(只表示大小,如内存地址)。如果我们把这些位解释为无符号整数,我们漂亮的加法/减法器机器还能工作吗?例如,在8位中,11111111 可能是 −1-1−1,也可能是 255255255。

这是故事中最深刻的部分:无论你使用哪种解释,硬件产生的结果位模式完全相同。机器完全不关心你的意图。原因在于系统的基础数学。N位有符号二进制补码算术和N位无符号算术都是在模 2N2^N2N 下运行的系统。

硬件操作 S=A+(bitwise NOT B)+1S = A + (\text{bitwise NOT } B) + 1S=A+(bitwise NOT B)+1 是一个数学真理的物理实现。BBB 的按位取反,我们记作 B‾\overline{B}B,等价于 (2N−1)−B(2^N - 1) - B(2N−1)−B。因此,电路计算: S=A+B‾+1=A+((2N−1)−B)+1=A−B+2NS = A + \overline{B} + 1 = A + ( (2^N - 1) - B ) + 1 = A - B + 2^NS=A+B+1=A+((2N−1)−B)+1=A−B+2N 在一个模 2N2^N2N 的系统中,加上 2N2^N2N 就等于加上零——它只是把你带回起点。所以,硬件计算出的结果在模 2N2^N2N 意义下与 A−BA - BA−B 同余。只要答案在各自的范围内,这个结果在有符号和无符号系统中都是正确的N位表示。这种硬件机制与模运算抽象数学之间的深度统一,证明了其底层原理的力量和一致性。

当魔法失效:溢出及其他怪事

我们的二进制补码系统很强大,但并非万无一失。它的魔法在N位的限制内运作。当减法的真实结果太大或太小,无法表示时会发生什么?这种情况被称为​​溢出​​。

考虑一个8位有符号系统,其数字范围从 −128-128−128 到 +127+127+127。如果我们计算 100−(−50)100 - (-50)100−(−50),真实结果是 150150150。这个值超出了我们的可表示范围。硬件会尽职地执行加法并产生一个二进制结果,但该结果将是无意义的,它会绕着模运算的圆环回绕,落入负数区域。

有趣的是,对于减法 A−BA-BA−B,溢出只可能在操作数 AAA 和 BBB ​​符号不同​​时发生。

  • 如果 AAA 是正数而 BBB 是负数,你计算的是 A+∣B∣A + |B|A+∣B∣,这可能超过最大正值。(例如,100−(−50)=150>127100 - (-50) = 150 > 127100−(−50)=150>127)。
  • 如果 AAA 是负数而 BBB 是正数,你计算的是 −(∣A∣+B)-(|A| + B)−(∣A∣+B),这可能比最小负值还要小。(例如,−100−50=−150<−128-100 - 50 = -150 < -128−100−50=−150<−128)。 如果 AAA 和 BBB 符号相同,它们差的绝对值永远不会大于它们自身的绝对值,所以溢出是不可能的。

处理器如何知道这种情况已经发生?它使用了另一个巧妙的技巧。它查看与最高有效位(符号位)相关的进位位。让我们把进入符号位列的进位称为 Cn−1C_{n-1}Cn−1​,离开它的进位称为 CnC_{n}Cn​。当且仅当这两个进位不同时,溢出发生:V=Cn⊕Cn−1\mathbf{V = C_{n} \oplus C_{n-1}}V=Cn​⊕Cn−1​。直观地说,这种情况意味着算术产生的结果太大(或太小),以至于错误地翻转了符号位,而进位的不匹配就是确凿的证据。

二进制补码世界还有其他有趣的怪癖。

  • ​​最负的数:​​ 最负的数的负数是什么?在一个8位系统中,这是 −128-128−128,即 10000000210000000_2100000002​。如果我们让机器计算它的二进制补码(以对其取负),它返回的还是 10000000210000000_2100000002​,完全相同的数!。这是因为它的正数对应值 +128+128+128 无法在8位有符号范围内表示。这在我们的数字系统中造成了轻微的不对称。
  • ​​符号扩展:​​ 当处理不同位宽的数字时,比如从一个8位数字中减去一个4位数字,我们必须小心。如果4位数字是负数,比如 1101 (−3-3−3),我们不能简单地用前导零填充它变成8位;那样会得到 00001101 (+13+13+13)。我们必须执行​​符号扩展​​:将其符号位复制到新的、更高阶的位置。因此,4位的 1101 变成8位的 11111101,这正确地表示了 −3-3−3。

从一个避免构建复杂硬件的简单技巧开始,二进制补码减法的原理展开成一幅丰富的画卷,其中包含了优雅的机制、统一的数学概念以及对所有现代计算都至关重要的实际考虑因素。

应用与跨学科联系

既然我们已经探索了二进制补码减法的内部工作原理,我们可能会问:“那又怎样?”这仅仅是一个巧妙的数字技巧,一个供数学家和计算机理论家玩味的奇物吗?答案是响亮的“不”。这个简单而优雅的想法不仅仅是教科书中的一个脚注;它是整个数字世界赖以构建的基础支柱之一。它的美不仅在于其巧妙,更在于其深远的实用性。通过将减法转化为加法的一个特例,它在惊人的程度上简化了计算机硬件的设计,使得我们现在习以为常的速度、效率和复杂性成为可能。让我们踏上一段旅程,探寻这个强大思想出现的各个地方,从处理器的核心到高速计算的前沿。

通用算术机

想象你是一位设计算术逻辑单元(ALU)的工程师,ALU是计算机处理器的数学大脑。你的任务是制造一个至少能执行加法和减法的电路。一种天真的方法可能是设计两个完全独立、复杂的电路:一个用于加法,一个用于减法。这将浪费硅片上的空间、浪费能源,并且设计和验证起来都令人头痛。

然而,大自然提供了更优雅的途径。二进制补码表示法使我们能够统一这两个看似相反的操作。我们可以构建一个单一的、通用的电路来同时完成这两项工作!这个技巧非常简单。要计算 A−BA - BA−B,我们知道实际上必须计算 A+(B‾+1)A + (\overline{B} + 1)A+(B+1)。我们需要一种方法来有条件地翻转 BBB 的位(得到 B‾\overline{B}B)并有条件地加1。一个单一的控制信号,我们称之为 MMM(代表“模式”),可以指挥这整个过程。

我们如何有条件地翻转位?我们使用一个异或门。对于任何位 BiB_iBi​,操作 Bi⊕MB_i \oplus MBi​⊕M 在 M=0M=0M=0 时产生 BiB_iBi​,在 M=1M=1M=1 时产生 Bi‾\overline{B_i}Bi​​。所以,我们可以让 BBB 的每一位通过一个由我们的模式信号 MMM 控制的异或门。为了处理“+1”,我们只需将相同的模式信号 MMM 连接到加法器的初始进位 CinC_{in}Cin​。

当我们想做加法(A+BA+BA+B)时,我们设置 M=0M=0M=0。异或门什么也不做(Bi⊕0=BiB_i \oplus 0 = B_iBi​⊕0=Bi​),初始进位为0。电路计算 A+B+0A + B + 0A+B+0。当我们想做减法(A−BA-BA−B)时,我们设置 M=1M=1M=1。异或门反转 BBB 的所有位(Bi⊕1=Bi‾B_i \oplus 1 = \overline{B_i}Bi​⊕1=Bi​​),初始进位为1。电路计算 A+B‾+1A + \overline{B} + 1A+B+1。瞧!我们用最少的额外硬件创建了一个组合式加法-减法器。这个基本设计几乎是每一台计算机的核心。这种抽象逻辑不仅仅是书本中的图表;它直接转化为像Verilog这样的硬件描述语言,工程师们在其中实例化加法器模块和异或门阵列来构建这些多功能的算术单元。控制逻辑甚至可以由数据本身驱动,创建出专门的电路,例如,根据其中一个数字的符号来决定是加还是减。

门卫:处理现实的极限

我们优雅的机器虽然强大,但并非万无一失。它在有限数量的位上运行——4、8、32、64位——这意味着它在一个有限的数字范围内工作。如果我们试图计算一个超出此范围的结果会发生什么?例如,在一个可以表示从-128到127的8位有符号系统中,100+100100 + 100100+100 是多少?答案是200,它装不下了。这被称为​​溢出​​,是一个严重的错误。一个无法处理大额款项的银行系统,或一个因溢出而错误计算位置的飞机导航系统,都将是灾难性的。

我们的系统不仅必须计算,还必须知道其计算何时无效。幸运的是,二进制补码提供了另一个优雅的时刻。检测减法(A−BA-BA−B)中的溢出不需要复杂的二次计算。它可以通过仅观察所涉及数字的符号来推断。溢出只可能发生在我们从正数中减去一个负数(例如,100−(−50)100 - (-50)100−(−50))或从负数中减去一个正数(例如,(−100)−50(-100) - 50(−100)−50)时。在第一种情况下,我们实际上是在相加两个正数;如果结果是负数,那就有问题了。在第二种情况下,我们是在相加两个负数;如果结果是正数,那就不对劲了。

这个简单的观察转化为一段优美的布尔逻辑。设 AsA_sAs​、BsB_sBs​ 和 SsS_sSs​ 分别为操作数和结果的符号位,溢出标志 VVV 仅在两种情况下被置位:(AsA_sAs​ 为正,BsB_sBs​ 为负,且 SsS_sSs​ 为负)或(AsA_sAs​ 为负,BsB_sBs​ 为正,且 SsS_sSs​ 为正)。这个逻辑,V=As‾BsSs+AsBs‾Ss‾V = \overline{A_s} B_s S_s + A_s \overline{B_s} \overline{S_s}V=As​​Bs​Ss​+As​Bs​​Ss​​,构成了一个简单的“守护”电路,它监视着最高有效位,并在结果不合逻辑时发出警报。它确保处理器能够信任自己的计算,这是从记录故障代码的工业控制器到任务关键型软件的一切事物的关键特性。

说不同的语言:与世界接口

数字世界并非铁板一块。为不同目的在不同时期设计的不同系统,通常使用不同的方式来表示数字。一个现代处理器核心可能完全基于二进制补码,但它可能需要与一个使用“符号-数值”表示法的遗留设备通信,这是一种用一位表示符号,其余位表示绝对值的格式。二进制补码ALU必须充当通用翻译器。为了执行像 C=A−BC = A-BC=A−B 这样的操作,其中 AAA 和 BBB 是符号-数值表示法,ALU必须首先将两个数字都转换为其原生的二进制补码,用其高效的硬件执行减法,然后将二进制补码结果转换回符号-数值表示法以供外部世界使用。这个转换、计算、再转换的过程,是不同“世界观”的系统如何成功协作的一个缩影。

一个更常见的桥梁是计算机的二进制世界和人类的十进制世界之间的桥梁。我们以十的幂来思考。计算器、收银机和数字显示器都使用十进制数字。为了处理这个,计算机使用二进制编码的十进制(BCD),其中每个十进制数字(0-9)由一个4位块表示。当我们想减去BCD数时,我们可以再次利用我们的二进制补码减法器。然而,二进制规则并不总是与十进制规则一致。二进制减法的结果可能是一个不对应于有效十进制数字的4位模式(即大于9),或者指示了需要向下一位“借位”。一个聪明的设计师会在主减法器之后增加一个“校正”阶段。这个阶段检测BCD规则何时被违反——例如,通过在二进制补码操作后检查传出进位位——并应用一个修正,使结果回到有效的BCD格式。这种将通用二进制引擎与专门校正单元分层结合的方式,展示了数字设计的模块化和强大功能。

对速度的不懈追求

在计算领域,正确性是根本,但速度为王。对于实时信号处理、图形渲染和科学模拟等应用,算术运算必须以极快的速度进行。简单的行波进位加法器,其中进位从一位“行波”到下一位,对于这些任务来说太慢了。延迟与位数 nnn 成正比。为了打破这种依赖关系,工程师们发明了超前进位加法器(CLA)。CLA使用更复杂的逻辑来并行计算所有进位,从而显著减少延迟。

在这里,加法和减法的统一性再次大放异彩。由于减法只是伪装的加法,我们为加速加法而开发的任何技术都可以直接应用于减法。要构建一个超前进位减法器,我们使用完全相同的CLA架构。唯一的变化在于初始的“生成”(GiG_iGi​)和“传播”(PiP_iPi​)信号。对于减法 A−BA-BA−B,我们加法器的输入是 AAA 和 B‾\overline{B}B。因此,我们只需根据 AiA_iAi​ 和 Bi‾\overline{B_i}Bi​​ 而非 AiA_iAi​ 和 BiB_iBi​ 来定义我们的 GiG_iGi​ 和 PiP_iPi​ 信号。其余的高速机制无需修改即可工作。

将对速度的追求推向极致,会引导我们进入迷人而奇特的计算机架构,如剩余数系统(RNS)。RNS通过将一个大数分解为几个较小的、独立的“剩余数”,打破了对长进位链的依赖。例如,一个数可以用它除以一组模数(如 {2n−1,2n}\{2^n-1, 2^n\}{2n−1,2n})所得的余数来表示。RNS的魔力在于,对大数的减法(以及加法和乘法)可以通过在每个小剩余数上完全并行地执行减法来完成,它们之间无需通信。

在模数为 {2n−1,2n}\{2^n-1, 2^n\}{2n−1,2n} 的系统中,我们需要两个专门的减法器并排运行。用于模数 m2=2nm_2 = 2^nm2​=2n 的通道非常适合我们标准的、高效的n位二进制补码减法器。然而,用于模数 m1=2n−1m_1 = 2^n-1m1​=2n−1 的通道,则更适合使用反码算术,它有一种自然的“循环进位”机制,能够优雅地处理模运算的回绕。因此,一个高性能的RNS减法器变成了一场优美的二重奏,由两种不同但相关的算术技术组成,每种技术都被选择为其特定任务提供最高效率,并行工作以达到单个、单片处理器无法企及的速度。

当出现问题时:故障分析之美

即使是设计最完美的机器也可能出现故障。制造缺陷、辐射或简单的磨损可能导致一根导线固定在某个恒定值,如0或1。如果我们的加法-减法器中,本应在减法时为1的初始进位 CinC_{in}Cin​,永久地固定在了0,会发生什么?

对原理的深刻理解使我们能够成为数字侦探。预期的操作是 S=A+B‾+1S = A + \overline{B} + 1S=A+B+1。出现故障后,电路现在计算的是 Sfaulty=A+B‾+0S_{faulty} = A + \overline{B} + 0Sfaulty​=A+B+0。这在算术上意味着什么?我们知道 BBB 的二进制补码是 B‾+1\overline{B} + 1B+1。因此,B‾\overline{B}B 就是 BBB 的二进制补码减1。所以,故障电路正在计算 A+(−B−1)A + (-B - 1)A+(−B−1),也就是 A−B−1A - B - 1A−B−1。这台机器的计算结果总是偏小1。通过观察这种特定的错误模式,工程师可以推断出电路内部确切的物理故障。这种从观察到的行为追溯到根本物理原因的能力,证明了建立在二进制补码基础上的逻辑的清晰性和可预测性。

从你笔记本电脑的中央处理器,到网络路由器或数字手表中的专用电路,二进制补码减法的原理是一个无名英雄。这是一个关于统一的故事,一个在复杂中寻找简单的故事,也是一个抽象数论与具体硬件工程之间非凡协同作用的故事。它是一个完美的例子,说明一个单一、优美的思想如何在不同学科中回响,从而催生了一个技术世界。