使用二进制补码进行逐位减法溢出

时间:2013-02-05 23:30:51

标签: c bit-manipulation bitwise-operators

当使用二进制补码执行逐位减法时,如何知道何时应忽略溢出?我读过的几个网站都说过溢出只是被忽略了,但这并不总是有效 - 溢出对-35 - 37等问题是必要的,因为需要额外的数字来表达-72的答案。

编辑:这是一个例子,使用上面的等式。

35到二进制 - > 100011,找到两个补码,使其为负数:011101

37到二进制 - > 100101,找到两个补码,使其为负数:011011

执行上述术语的添加(二进制等效-35 - 37):

011101
011011
------
111000

将两个补码转换回正数:001000

以上是许多网站(包括学术网站)所说的答案应该是,因为你忽略溢出。然而,这显然是不正确的。

1 个答案:

答案 0 :(得分:5)

当结果无法在目标数据类型中表示时,会发生溢出。值-72可以用char表示,这是一个带符号的8位数量......在你的例子中没有溢出。也许你在进行逐位减法时考虑borrow ...当你从'1'中减去'0'时需要borrow从下一个更高位的位置。在进行减法时,你不能忽略借用。

-35 decimal is   11011101 in two's complement 8-bit
+37 decimal is   00100101 in two's complement 8-bit

从最低有效位到最高有效位从右到左,你可以在-35中从每个位中减去+37中的每一位,直到你到达第5位(从右边的位0开始计数)。在位位置5,您需要从'1'中减去'0',因此您需要在-35中从位位置6(下一个更高位的位)借位,这恰好是'1'先验借钱。结果看起来像这样

-35 decimal is   11011101 in two's complement 8-bit
+37 decimal is   00100101 in two's complement 8-bit
                 --------
-72 decimal is   10111000 in two's complement 8-bit

结果是否定的,你在8位二进制补码中的结果有高位设置(第7位)......这是负数,因此没有溢出。

更新:我认为我看到了混淆的地方,并且我声称Adding and subtracting two's complement的答案在您说discard the carry (indicates overflow)时是错误的。在那个答案中,他们通过使用二进制补码然后加法将第二个操作数转换为负数来进行减法。那很好 - 但是在这种情况下,进位并不代表溢出。如果你在N位(编号为0到N-1)中添加两个正数,并且你考虑这个无符号算术range 0 to (2^N)-1并且你得到位置N-1的进位然后你有溢出 - 两个正的总和数字(解释为无符号以最大化可表示的正数的范围)不应生成最高位(位N-1)的进位。因此,当添加两个正数时,您可以通过说

来识别溢出
  1. 当您将它们解释为无符号和
  2. 时,必须不执行N-1位
  3. 当解释为有符号(二进制补码)
  4. 时,位N-1的结果必须为零

    但请注意,处理器不区分有符号和无符号加法/减法...它们设置溢出标志以指示 if 您将数据解释为已签名然后结果无法表示(错误)。

    这是a very detailed explanation of carry and overflow flag。该文章的内容是这个

    • unsigned算术中,观察进位标志以检测错误。
    • unsigned算术中,溢出标志告诉你没有什么有趣的。

    • signed算术中,观察溢出标志以检测错误。

    • signed算术中,进位标志告诉你没有什么有趣的。

    这与definition of arithmetic overflow in Wikipedia表示一致

      

    大多数计算机区分两种溢出条件。当加法或减法的结果(考虑操作数和结果为无符号数)不适合结果时,会发生进位。因此,在添加或减去被解释为无符号值的数字后检查进位标志很有用。当结果没有人们可以根据操作数的符号预测的符号时(例如,当添加两个正数时为负结果),就会发生溢出。因此,在添加或减去以二进制补码形式表示的数字后检查溢出标志是有用的(即它们被认为是有符号数字)。