【问题标题】:How is overflow detected when doing binary subtraction进行二进制减法时如何检测溢出
【发布时间】:2021-10-05 12:25:34
【问题描述】:

假设我们有 3 位可以玩。我将用 2 的补码表示正负 3:

+3 = 0b011
-3 = 0b101

在进行加法时,当像这样(-3) + (+3)

发生溢出时,您总是会有一个悬空位
  1 0 1
+ 0 1 1
  -----
1 0 0 0

但是减法(-3) - (+3)呢?

  1 0 1
- 0 1 1
  -----
  0 1 0

0b0102,这不是我们预期的正确结果 -6。有溢出 并且额外的位甚至没有生成,那么如何检测到有溢出?

我想解决这个问题的正确方法是先签署扩展输入?

【问题讨论】:

  • 3 位 2 的补码只能处理 -4 .. +3 范围内的值,所以 -6 换行到 +2。 “期望”一个不可编码的值是没有意义的,但我认为这只是笨拙的措辞来谈论正确的数学结果。当输入符号相反且输出符号与第一个操作数不同时,您可以检测到减法溢出。
  • 可以肯定地说,在进行有符号算术时,我们总是必须先将输入扩展为结果类型?
  • 在 8 位字节中存储 3 位数字可以通过多种方式完成:忽略高 5 位,符号扩展 3 到 8,或将 3 位数字移到上端,以便将被忽略的 5 位是低 5 位。如果你选择第一种方式,你会失去处理器的一些特性,比如溢出标志和符号标志,但是还有其他方法可以获取这些信息。
  • @ErikEidt 有道理。我想这不是一个规则,这取决于是否要使用高位(加宽)位。
  • @ErikEidt 您提到的也可以应用于各种尺寸,即 8->32、8->64 等。

标签: assembly cpu-architecture twos-complement integer-arithmetic


【解决方案1】:

如何在逻辑中检测到有符号溢出

(-3) - (+3) = (-3) + (-3) = (-3) + (~3) + 1

使用小学数学和二进制补码

    1
  101
+ 100
======

完成它

 1011
  101
+ 100
======
  010

当msbit的进位和进位不同时会发生SIGNED溢出。我们在这里看到。另一种说法是,使用反转的操作数 B,如果操作数的 msbits 相同并且结果不是相同的值,则它是有符号溢出。

请注意,msbit 的进位是非借位,因此 1 表示没有借位,0 表示有借位。一些处理器架构反转进位并将其称为借位,而另一些则没有。任何一种解决方案都有效,您只需让比较逻辑匹配并用借位减去。

对于小学数学,我们可以继续添加列。如果我们可以简单地向寄存器添加一位,我们可以获得加法和减法的完整答案。对于乘法,我们需要两倍的位数。对于 3 位操作数,我们需要 6 位结果才能不溢出。作为补充,理想情况下,您需要一个 6 位分子用于除法的三位除数。并非所有指令集都提供此功能。是的,对于有符号操作,您需要对扩展进行签名,对于无符号操作,您需要零填充,因此有符号乘法和无符号乘法之间的区别。对于 3 位结果(相乘),有符号/无符号无关紧要(像小学一样在纸和铅笔上做,这应该很明显)。同样,对于 3 位加法或减法,无需知道无符号与有符号。

虽然正常的解决方案是用进位加法和用借位减法,但加法和减法。 -3 - +3 给出 -6,我们无法用 3 位表示,我们需要 4,但如果我们假设 3 位寄存器,那么我们唯一能做的就是 6。这意味着我们真的在尝试做 111101 - 000011。

     1011
   111101
  +111100
    ======
      010

如果我们在视觉上这样做并将其切成两半

     1   011
   111   101
  +111   100
  ============
         010

我们可以使用第二条指令完成减法(借位减法)

  1111 
   111 
  +111 
  =====
   111
   

111010 是 -6,没有溢出。关键是把下半部分的进位拿到上半部分的进位。

如果体系结构在减法的过程中反转进位,那么它需要在途中将借位反转为带借位的减法,否则如果它没有将它反转出 sub 则不要反转它进入 sbb. add 和 adc(带进位相加)的工作方式相同,只是没有反转,进位位作为 msbit 的进位进入 adc。

乘法并不那么简单,它不是一个位的东西,您需要整个寄存器的位,因此某些架构会给您 3 位乘以 3 位等于 6 位有符号和无符号的乘法指令。但是对于加法和减法并没有真正的需要,使用进位位和一条附加指令以及包含其余位的内存/寄存器。您可以添加/减去尽可能多的内存/寄存器,1000 位加 1000 位很容易,它只是一个加法和一堆 adc 连续。

【讨论】:

  • 感谢您提供有关when do we sign extend the input? 的信息,当我们预计输出大于输入时,是否足以说明我们这样做?
  • 不,我的意思是,当您相乘并且结果比输入宽,或者当您相加并且结果变得比原始数据类型大时,我试图确认这些情况是您签署扩展输入。
  • true 但是即使进行加法/减法,如果输出增长大于输入数据类型,您仍然需要对扩展进行签名,您可以对输入进行扩展,或者只是对输出进行扩展。即添加两个可能溢出到 16 位半字的 8 位字符。
  • 真的,这是最初的问题,它有点偏离了符号扩展等等,但感谢您回答我最初的问题。关于addition with carry 我猜它更具体到 x64,其他架构可能允许溢出到符号位(以及设置溢出标志)。
  • 现在我理解了这个问题,所以重新编写了答案。
【解决方案2】:

可以通过(进位到 MSB)异或(进出 MSB)来创建溢出标志。

【讨论】:

猜你喜欢
  • 2012-07-06
  • 1970-01-01
  • 2015-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多