【问题标题】:Overflow in bitwise subtraction using two's complement使用二进制补码进行按位减法溢出
【发布时间】:2013-02-05 23:30:51
【问题描述】:

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

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

35 转二进制 -> 100011,求补码使其为负:011101

37 转二进制 -> 100101,求补码使其为负:011011

执行上述项的加法(-35 - 37 的二进制等效项):

011101
011011
------
111000

取二进制补码转换回正数:001000

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

【问题讨论】:

  • 显然那些网站并没有描述如何按位计算-32 - 37 :-)
  • This answer 说明了这一点,以及this academic webpage 上的第 4 步。 This PowerPoint(Google 查看器链接)也在幻灯片 9 上显示。
  • 什么是按位减法?你的意思是2的补码中的减法?如果是这种情况,那么您的问题应该是,2 的补码加法宽度为N(例如)的负整数何时溢出?
  • 你能解释一下你对“按位”减法的期望吗?这和减法有区别吗? (您使用的是 - 运算符,所以我不知道您所说的按位是什么意思?)另外,我在您的示例中没有看到任何溢出?你可以在这里查看hackersdelight.org,了解一些方便的溢出检测算法。此外,根据您的硬件,有时会在发生溢出时设置一个寄存器位(但这只是在它发生之后)。
  • 刚刚在主帖中添加了一个使用-35 - 37 的示例,这有帮助吗?

标签: c bit-manipulation bitwise-operators


【解决方案1】:

当结果无法以目标数据类型表示时,就会发生溢出。值 -72 可以用 char 表示,它是一个有符号的 8 位数量......在您的示例中没有溢出。也许您在进行按位减法时正在考虑borrow...当您从'0' 中减去'1' 时,您需要从下一个高阶位位置中减去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 位,您需要从 '0' 中减去 '1',因此您需要从 -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. 当您将 N-1 位解释为无符号时,必须没有进位,并且
  2. 当解释为有符号(二进制补码)时,位 N-1 中的结果必须为零

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

这里是a very detailed explanation of carry and overflow flag。那篇文章的要点是这样的

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

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

  • signed 算术中,进位标志告诉您任何有趣的事情。

这与definition of arithmetic overflow in Wikipedia 所说的一致

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

【讨论】:

  • 最初的问题是由一个需要 6 位数字的家庭作业问题引发的,因此我的(刚刚添加的)示例是这样编写的。很多网站(请参阅我对主帖的第一条评论)说简单地忽略溢出,但事实并非如此。
  • 好吧,这改变了事情......如果你被限制为 6 位数字,那么你在表示 -35 和 +37 时会遇到问题,这两个都需要 7 位二进制补码来表示。在二进制补码中,6 位数的范围是 -32 到 +31(二进制 100000 到二进制 011111)。
  • 正如我在评论中指出的那样,试图以不考虑保留符号位的位深度表示有符号整数是不允许的,我 think 是所提出的问题值的基本问题。所以我相信这个答案是准确的。
  • 啊,更新版本很有意义。 (嗯,原来的版本有,但这个更好。:))非常感谢!
猜你喜欢
  • 1970-01-01
  • 2021-10-27
  • 1970-01-01
  • 2018-05-26
  • 2012-09-21
  • 1970-01-01
  • 1970-01-01
  • 2011-11-24
  • 1970-01-01
相关资源
最近更新 更多