【问题标题】:overflow during operation a+(-a)操作期间溢出 a+(-a)
【发布时间】:2013-07-15 03:23:42
【问题描述】:

假设 a=1

1+(-1) =0

但使用 4 位二进制,使用 2 的补码

0001+1111=10000 ~ 0000

有符号整数溢出不是未定义的行为吗?

对于这种微不足道的结果,我们是否依赖未定义的行为,或者我错过了什么。

from wikipedia: 如果左边的两个进位位(在这些示例中位于顶行最左侧的位)均为 1 或均为 0,则结​​果有效;如果左两个进位位是“1 0”或“0 1”,则发生符号溢出。

【问题讨论】:

  • 为什么这与 8 位、16 位等有什么不同?如果你将000...01 添加到111...11 你会得到000...00
  • 这可能有助于讨论进位和溢出:en.wikipedia.org/wiki/Two's_complement#Addition
  • 当您添加带有相反信号的有符号数时,永远不会出现溢出,您看到的是进位数传播以使更大的容器能够正确运行。
  • “编辑:来自维基百科链接”哪个链接?
  • 当维基百科谈到左边的两个进位时,它清楚地指出它们不是在你的例子中最左边的那个。再次查看维基百科页面11111 111 (carry)

标签: c++ c binary overflow twos-complement


【解决方案1】:

添加带有相反符号的有符号数字永远不会产生溢出。实际上,硬件通常有两个与加法相关的标志位,即溢出位和进位位。

只有在容器不够大而无法正确表示数字时才会设置溢出位。对于有符号数,硬件在分析每个操作数的符号位和结果的符号后设置该位。如果操作数的符号不同,则永远不会设置该位。否则,如果操作数的信号相等,则分析结果的符号。如果与操作数不同,则设置该标志,表示结果溢出。

在你的例子中,每个操作数的符号不同,所以没有溢出,但是如果你想使用大容器来保持操作正确,这个操作会产生一个进位。

【讨论】:

  • 我以为你每次写“signal”时的意思都是“sign”。
【解决方案2】:

有符号整数溢出未定义,但我看不出这会是什么问题,因为您将两个有符号数字相加,结果确实在范围内。

对于 4 位整数类型,溢出将添加 7+7,其中结果应为 14,不适合 -2^3..2^3-1 范围

【讨论】:

  • 我们知道结果在范围内,但是在机器级别添加 7+7 作为 111+111=1110 与添加 4+(-3) 作为 0100+1101=10001~0001 没有什么不同。
  • @ZxcvMnb:这取决于硬件。为有符号值添加是否会添加所有位并设置进位标志,或者它会在不修改进位标志的情况下产生结果由硬件定义。
  • 此外,在 4 位算术中不能存在未定义的溢出,因为小于 int 的类型被提升为 int 并且 int 至少为 16 位宽。对于较小的类型/位域,只有实现定义的从int 到目标类型/位域的转换。
  • @PascalCuoq:为了简单起见,他显然只使用了 4 位,他的问题随着任何有限的位数而扩大。
  • @PascalCuoq:我正在考虑一个假设的架构,其中int 可能只有 4 位(以避免不得不提取大量数字)。但是是的,在执行操作之前,整数类型被提升为int
【解决方案3】:

底层表示可能在内部使用溢出来获得正确的结果,但这无关紧要。仅当操作的结果超出类型范围时,行为才被定义。

【讨论】:

  • 那么你是说未定义的行为取决于我们的结论是否超出范围而不是位实际溢出?
  • @ZxcvMnb 从 language 的角度来看,1+-1 不会溢出,因此它不是未定义的行为。 编译器硬件做什么是100%不相关的。
【解决方案4】:

这是未定义的行为,但我不确定我是否理解您的问题。您是在问为什么它在该示例中有效?因为这些值在范围内,结果也在范围内。考虑

-8 + -1

4位

1000 + 1111 -> 10111 -> 0111 -> 7. 这里我们不再有正确答案了

【讨论】:

  • “这是未签名的行为”?
  • 哇...可怕的错字。累的时候不应该回答问题。感谢您额外的一双眼睛,固定
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多