【问题标题】:How can I stop OverflowException being thrown on integer division?如何停止在整数除法上抛出 OverflowException?
【发布时间】:2009-08-19 15:35:55
【问题描述】:

当我不想要 OverflowException 时(或者我认为是这样),我收到了它们。我正在执行一些奇怪的计算,我希望这些值会溢出,丢弃溢出的位。看来我无法让它正常工作。基本上这是一对 i 和 j,它发生在我迭代巨大的集合(int.MinValue 到 int.MaxValue)时。

// i and j are ints
// i is -2147483648
// j is -1
var x = i / j;

// I also tried using unchecked keyword, but it doesn't help    
var x = unchecked(i / j);

更新:

-2147483648 / -1 的预期数学值是 2147483648。但是,这个特定的代码并没有真正尝试找到数字。这是一系列难以理解的位操作的一部分。老实说,我什至不知道自己的意图是什么,因为我没有真正记录该方法,并且只需要一天时间就可以在我的头上引发严重的 WTF 泡沫。据我所知,它使用旨在处理此案的特殊代码按预期工作。

关于预期值:

由于 int 最多只能容纳 2147483647,我希望丢弃溢出产生值 0。

如果我对此有任何了解,那可能是文​​档对于晦涩的方法的重要性。

【问题讨论】:

  • 我希望你在实际代码中有一个 try/catch 块?
  • 不,我不知道。但是,我确实确保不会除以零。
  • 关于您的编辑:您是否希望 int.MaxValue + 1(也等于 2147483648)溢出为零?
  • 不,我不会。无论如何,我想我已经解决了这个问题(尽管我认为检查它并不好)。谢谢你的帮助。如果有人为预期行为提出“干净”的解决方案,请随时发布。

标签: c# .net math overflowexception


【解决方案1】:

我相信这是唯一您会遇到此异常的情况。这是Int32 范围内唯一可以溢出的分区。 (当然有除以零,但这是一个不同的例外。)

所以如果你想避免OverflowException只有需要处理这种情况。你想让它做什么?编写一个方法来发现这种精确情况,否则进行正常除法。

注意:这也是为什么您不应该尝试通过否定结果来反转比较的原因。如果您想按降序而不是升序对某些内容进行排序,那么不要使用-Compare(x, y),而是使用Compare(y, x)。否定不会int.MinValue 提供溢出(除非您处于已检查的上下文中) - 它只是默默地返回int.MinValue

【讨论】:

  • 从您的帖子中我了解到,否定 int.MaxValue 会返回 int.MinValue,而不是溢出,但否定 int.MaxValue 会返回 int.MinValue + 1(因为范围在 2147483647 和 - 2147483648)。此外,否定 int.MinValue 是它应该溢出的地方,但比 - c# 愉快地再次返回 int.MinValue (或抛出内部检查 {})。是我误解了你的意思,还是打错字了?
  • 错字 - MaxValue 应该是 MinValue。
【解决方案2】:

二进制补码表示整数的范围从 2^32 - 1 到 -2^32,因此 -2147483648 / -1 返回一个无法用 int 表示的数字。

您可以尝试将其放入long。在这种情况下没有理由使用var

【讨论】:

  • 其实,做这样的事情:x = i / j;,其中x是long没有帮助,整个操作必须在long上执行,所以x = (long)i / j;会起作用,并且因为结果会很长,所以可以在这里使用 var (虽然我个人不喜欢在这种情况下使用 var ,但那是完全不同的故事。
  • 我很确定 OP 知道这一点。他的问题是 unchecked 不能按应有的方式工作。 unchecked 应该允许的唯一例外是 div by 0。在此示例中,x 是 int 还是 var 无关紧要。
【解决方案3】:

您可以通过与Int64 进行一些转换来解决此问题:

var x = (int)((long)i / j);

【讨论】:

  • 不起作用。 x-2147483648 结尾,正确答案是2147483648。正如 Pike65 正确指出的那样,这个数字不能用带符号的 32 位整数表示。解决此问题的唯一方法是使用其他类型,例如 long
  • @jpbochi:OP 期望它溢出,并希望它这样做而不抛出异常。相当于 2147483648 的“溢出”Int32 是 -2147483648。
  • @jpbochi,试试这个:var x = unchecked(int.MaxValue + 1);
【解决方案4】:

你这样做。你为什么要在这里使用var?它失去了向您显示算术结果类型的能力,全部用于保存 1 个字符...

long x = (long)i / j;

如果你想要饱和,你可以:

int x = (int)Math.Min((long)i / j, int.MaxValue);

【讨论】:

  • 问题表明 OP 希望结果是“溢出”int,而不是 long:“我希望值溢出,丢弃溢出的位”。
  • 老实说,拥有 var 或 int 是无关紧要的,因为类型的评估将导致 var 采用 int 的类型。我选择了 var,以防我不得不长时间编写类似的代码,如果我使用 var,我就不必进行大量重构。
猜你喜欢
  • 1970-01-01
  • 2011-10-03
  • 1970-01-01
  • 2017-08-04
  • 2014-12-23
  • 2017-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多