【问题标题】:How does the CPU do subtraction?CPU是怎么做减法的?
【发布时间】:2011-04-26 16:58:49
【问题描述】:

我有一些基本的疑问,但每次我坐下来尝试面试问题时,这些问题和我的疑问都会冒出来。

假设 A = 5,B = -2。假设A和B都是4字节,那么CPU是怎么做A + B加法的?

我知道 A 的符号位 (MSB) 为 0 以表示正值 B 的符号位为 1,表示负整数。

现在在C++程序中,我想打印A + B,ALU(算术逻辑单元)的加法模块首先检查符号位,然后决定做减法,然后按照减法的过程。减法是怎么做的将是我的下一个问题。

A = 5
B = 2

我想做A - B。计算机将取 B 的 2 的补码并添加 B 的 A + 2 的补码并返回(在丢弃左侧的多余位之后)?

A = 2
B = 5

A - B。这种情况下电脑是怎么做的?

我知道任何 if-then 等条件逻辑都将在 ALU 内的硬件中完成。计算 2s 补码等,丢弃多余的位都将在 ALU 内部的硬件中完成。 ALU 的这个组件长什么样子?

【问题讨论】:

  • ALU 看起来像这样:en.wikipedia.org/wiki/…
  • 负数是对应正数的 2 的补码 - 而不仅仅是符号位的变化。

标签: math cpu cpu-architecture subtraction alu


【解决方案1】:

我们使用2's-complement 的全部原因是,无论数字是正数还是负数,加法都是相同的——没有特殊情况需要考虑,例如1's-complementsigned-magnitude 表示。

所以要找到A-B,我们可以将B取反并加;也就是说,我们找到了A + (-B),并且因为我们使用的是 2 的补码,所以我们不用担心(-B) 是正数还是负数,因为加法算法的工作原理都是一样的。

【讨论】:

  • 在 1 的补码中也没有特殊情况需要考虑。您只需添加 2 个数字并添加进位即可。只有符号大小需要处理符号位
  • 请注意,如果真正的减法有借位,而不是假设的 A + (-B) 加法,则某些 ISA(如 x86)会设置进位标志输出。这种实现可能性不会改变(-1) - (-2)(即0xFF - 0xFE)导致CF=0的事实。 ARM 则相反:减法后的 C 标志是 !borrow 结果,而 ARM 的 sbc 指令也有相应的行为。
【解决方案2】:

从 2 位或 3 位的角度进行思考,然后了解这些东西可以扩展到 32 或 64 位或任意多位。

首先,让我们从十进制开始

 99
+22
===

为了做到这一点,我们将进行一些“随身携带”。

11
 99
+22
===
121

9加2是1进1,1加9加2就是2进1……

要注意的是,要添加两个数字,我实际上需要三行,至少对于其中的一些,我可能需要能够添加三个数字。与 alu 中的加法器相同,每个列或位通道,单个位加法器,需要能够将两个输入和一个进位相加,输出是一位结果和一位进位。

既然你使用了 5 和 2,让我们做一些 4 位二进制数学

 0101
+0010
=====
 0111

我们不需要进行这个,但你可以看到数学是有效的,5 + 2 = 7。

如果我们想添加 5 和 -2

11
 0101
+1110
=====
 0011

正如预期的那样,答案是 3,这并不奇怪,但我们有一个执行。由于这是一个带有负数的二进制补码加法,所以它都可以工作,所以没有 if 符号位,二进制补码可以,所以我们不在乎只为加法器提供两个操作数。

现在如果你想做出细微的差别,如果你想从 5 中减去 2,你选择减法指令而不是加法。好吧,我们都知道,在二进制补码中取反意味着反转和加一。我们在上面看到,一个两输入加法器确实需要第三个输入来进行进位,以便它可以级联到加法器需要的宽度。因此,与其进行两次加法运算,不如将反转和加 1 作为第一个加法,真正的加法我们所要做的就是反转并设置进位:

了解没有减法逻辑,它会添加您输入的任何内容的负数。

    v this bit is normally zero, for a subtract we set this carry in bit
11 11
 0101 five
+1101 ones complement of 2
=====
 0011

你知道我们得到了相同的答案...对于任何一个操作数的实际值是什么都没有关系。如果是加法运算,则在进位位上放置一个零并将其馈送到加法器。如果它是减法运算,则将第二个操作数取反并在进位上放一个并将其馈送到同一个加法器。掉出来的东西都会掉出来。如果您的逻辑有足够的位来保存结果,那么一切正常,如果您没有足够的空间,那么您就会溢出。

溢出有两种,无符号和有符号。无符号很简单,它是进位位。有符号溢出与比较 msbit 列上的进位位与该列的进位位有关。对于我们上面的数学,您会看到该 msbit 列的进位和进位是相同的,两者都是一个。我们碰巧通过检查知道 4 位系统有足够的空间来正确表示数字 +5、-2 和 +3。 4 位系统可以表示 +7 到 -8 的数字。因此,如果你要添加 5 和 5 或 -6 和 -3,你会得到一个有符号溢出。

01 1
 0101
+0101
=====
 1010

了解 SAME 加法逻辑用于有符号和无符号数学运算,这取决于您的代码,而不是虚拟定义这些位是否被视为二进制补码有符号或无符号的逻辑。

对于上面的 5 + 5 情况,您会看到 msbit 列上的进位是 1,但进位是 0,这意味着 V 标志,有符号溢出标志,将由逻辑设置。同时,该位的进位,即 C 标志的进位标志,将不会被设置。当考虑无符号 4 位可以容纳数字 0 到 15 时,因此 5 + 5 = 10 不会溢出。但是当认为有符号的 4 位可以容纳 +7 到 -8 并且 5 + 5 = 10 是有符号溢出时,因此设置了 V 标志。

如果/当您有带进位指令的加法时,它们采用相同的加法器电路,而不是将进位输入零,而是输入进位标志。同样,借位减法,不是将进位输入 1,而是根据状态寄存器中进位标志的状态输入 1 或 0。

乘法完全是另一回事,二进制使乘法比使用十进制数学更容易,但你必须有不同的无符号和有符号乘法指令。除法是它自己独立的野兽,这就是为什么大多数指令集没有除法。许多没有乘法,因为它烧毁了门或时钟的数量。

【讨论】:

    【解决方案3】:

    你在符号位部分有点错误。它不仅仅是一个符号位 - 每个负数都转换为 2 的补码。如果你写:

    B = -2
    

    编译器编译成二进制时会这样:

    1111 1111 1111 1111 1111 1111 1111 1110
    

    现在当它想加 5 时,ALU 得到 2 个数字并将它们相加,一个简单的加法。

    当 ALU 收到一个减去它的命令时,它会得到 2 个数字 - 它对第二个数字的每一位都做一个 NOT,然后做一个简单的加法并再加 1(因为 2 的补码不是每个位 +1)。

    这里要记住的基本事项是,选择 2 的补码的目的正是为了不必为 2+3 和 2+(-3) 创建 2 个单独的过程。

    【讨论】:

      【解决方案4】:

      ALU(Arithmetic Logic Unit)的加法模块是否先检查符号位,然后决定做减法,然后再执行减法程序

      不,在一个和两个的补码中,加/减正数或负数之间没有区别。对于正值和负值的任意组合,ALU 的工作方式相同

      所以 ALU 基本上是在为A - BA + (-B),但它不需要单独的否定步骤。 设计者使用一个巧妙的技巧让加法器在相同的周期长度内同时执行 addsub,方法是只添加一个 muxer 和一个非门以及新的输入 Binvert 为了有条件地反转第二个输入。这是一个简单的 ALU 示例,可以执行 AND/OR/ADD/SUB

      Computer Architecture - Full Adder

      真正的加法器只是一个在 ⊞ 内带有加号的框,它将 ab~bcarry 相加在中,产生sum执行。它的工作原理是在二进制补码-b = ~b + 1,所以a - b = a + ~b + 1。这意味着我们只需要将 carry in 设置为 1(或对借入取反)并反转 第二个输入(即 b)。这种类型的 ALU 可以在各种计算机体系结构书籍中找到,例如

      补码-b = ~b所以要减的时候不要设置进位,否则设计是一样的。然而,二进制补码还有另一个优点:对有符号和无符号值的操作也同样有效,因此您甚至不需要区分有符号和无符号类型。如果类型是签名的,你需要add the carry bit back to the least significant bit作为补充

      通过对上述 ALU 进行一些简单的修改,它们现在可以执行 6 种不同的操作:ADD、SUB、SLT、AND、OR、NOR

      CSE 675.02: Introduction to Computer Architecture

      多位运算是通过连接上面的多个单位 ALU 来完成的。实际上,ALU 能够执行更多操作,但它们是为了节省空间而设计的,原理相似

      【讨论】:

      【解决方案5】:

      在 2 的补码表示法中:not B = -B -1-B = (not B) + 1。可以在电脑上或纸上检查。

      所以 A - B = A + (not B) + 1 可以这样执行:

      • 1 位非
      • 1 个增量
      • 1 次添加

      仅使用非和否定来低效地递增和递减是一个技巧。

      例如,如果您从寄存器中的数字 0 开始并执行:

      not, neg, not, neg, not, neg, ... 寄存器会有值:

      -1, 1, -2, 2, -3, 3, ...

      或者作为另外两个公式:

      not(-A) = A - 1
      -(not A) = A + 1
      

      【讨论】:

        猜你喜欢
        • 2017-05-19
        • 2012-08-25
        • 2011-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-06
        • 2018-06-16
        • 2010-09-11
        相关资源
        最近更新 更多