【问题标题】:How can I detect integer overflow on 32 bits int?如何检测 32 位 int 上的整数溢出?
【发布时间】:2014-02-09 14:21:16
【问题描述】:

我知道这样的话题被问了好几次,但是我的问题是关于完整的 32 位 int 的溢出。例如:

  11111111111111111111111111111111 +
  00000000000000000000000000000001 =
  00000000000000000000000000000000   //overflow!

我发现topic 有类似的问题,但是算法并不完美。

  11111111111111111111111111111111 +
  00000000000000000000000000000000 =
  00000000000000000000000000000000  //overflow!

有没有什么简单、快速、安全的检查方法?

【问题讨论】:

标签: java integer bit-manipulation integer-overflow integer-arithmetic


【解决方案1】:

Math.addExact 溢出时抛出异常

从 Java 8 开始,Math 类中有一组方法:

……以及长期的版本。

如果发生溢出,这些方法中的每一个都会抛出ArithmeticException。否则,如果它在范围内,它们会返回正确的结果。

加法示例:

int x = 2_000_000_000;
int y = 1_000_000_000;
try {
    int result = Math.addExact(x, y);
    System.out.println("The proper result is " + result);
} catch(ArithmeticException e) {
    System.out.println("Sorry, " + e);
}

看到这个code run live at IdeOne.com

对不起,java.lang.ArithmeticException:整数溢出

【讨论】:

    【解决方案2】:
    long test = (long)x+y;
    if (test > Integer.MAX_VALUE || test < Integer.MIN_VALUE)
       // Overflow!
    

    【讨论】:

    • x & y 是否被认为是 long 的?如果它们是 int 的,我认为这不会起作用(因为在长时间转换之前溢出不会被检测到);我说的对吗?
    • 你不正确。 X 在加法之前被强制转换(优先级)。 long+int int 被转换为 long,你最终得到 long+long。因此,整个操作以 64 位精度完成。
    • 好吧,所以强制转换优先于加法运算符。谢谢!
    【解决方案3】:

    试试这个方法:

    boolean isOverflow(int left, int right) {
        return right > 0
                ? Integer.MAX_VALUE - right < left
                : Integer.MIN_VALUE - right > left;
    }
    

    发件人:https://wiki.sei.cmu.edu/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow

    【讨论】:

    • 未检测到isOverflow(-47483648, -100000000) 中的溢出。
    • 这实际上不是溢出 :)
    【解决方案4】:

    可以通过两个操作数的最高有效位的逻辑表达式和(截断的)结果来检测溢出(我从 MC68030 手册中获取了逻辑表达式):

    /**
     * Add two int's with overflow detection (r = s + d)
     */
    public static int add(int s, int d) throws ArithmeticException {
        int r = s + d;
        if (((s & d & ~r) | (~s & ~d & r)) < 0)
            throw new ArithmeticException("int overflow add(" + s + ", " + d + ")");
        return r;
    }
    

    【讨论】:

    • Java 8 的 addExact 被编码为 if (((s ^ r) &amp; (d ^ r)) &lt; 0)
    【解决方案5】:

    我能想到的最直观的方法:将总和(或差)计算为long,然后将该总和转换为int,看看它的值是否发生了变化。

    long longSum = (long) a + b;
    int sum = (int) longSum;
    if (sum == longSum) {
        // sum contains the correct result
    } else {
        // overflow/underflow
    }
    

    请记住,在现代 64 位处理器上,使用 longs 的效率不低于使用 ints(可能相反)。因此,如果您可以在检查溢出或使用longs 之间进行选择,请选择后者。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-08-27
      • 1970-01-01
      • 1970-01-01
      • 2019-08-20
      • 1970-01-01
      • 2019-08-23
      • 2015-04-23
      相关资源
      最近更新 更多