如何防止Java代码中的整数溢出?

Mic*_*ael 30 java math integer overflow

可能重复:
如何检查Java中的两个数字相乘是否会导致溢出?

假设我有一个Java类方法,它使用*+操作.

int foo(int a, int b) {
  ... // some calculations with + and * 
}

如何确保不会发生溢出foo

我想我可以使用BigDecimal或替换所有+和*与"包装",如:

int sum(int a, int b) {
   int c = a + b;
   if (a > 0 && b > 0 && c < 0) 
     throw new MyOverfowException(a, b)
   return c;
}

int prod(int a, int b) {
   int c = a * b;
   if (a > 0 && b > 0 && c < 0) 
     throw new MyOverfowException(a, b)
   return c;
}

有没有更好的方法来确保intJava方法中不会发生溢出?

Aln*_*tak 23

以检查溢出的一种方式是有操作数升为(双原始操作数位长的)更大的类型然后执行该操作,然后查看是否所得到的值是原始类型,例如过大

int sum(int a, int b) {
    long r = (long)a + b;
    if (r >>> 32 != 0) {    // no sign extension
        throw new MyOverflowException(a, b);
    }
    return (int)r;
}
Run Code Online (Sandbox Code Playgroud)

如果您的原始类型是a long,则必须使用BigInteger更大的类型.


Ste*_*n C 20

从工程角度来看,这是一个难题.

安全编码的网站建议:

  • 使用先决条件; 即范围检查输入,以便溢出是不可能的,
  • 使用下一个较大的原始整数类型执行每个单独的算术运算并显式检查溢出,或
  • 使用BigInteger.

这篇Dobbs博士的文章建议创建一个原始算术方法库,它使用显式溢出检查来执行每个基本操作.(您可以将其视为上面第2点要点的实现.)但作者更进一步建议您使用字节码重写来替换算术字节码,并调用包含溢出检查的等效方法.

不幸的是,没有办法在Java中本机启用溢出检查.(但同样适用于许多其他语言;例如C,C++ ......)

  • “从工程的角度来看,这是一个难题。” -- 没那么难:只要在每次操作后生成机器码来检查溢出寄存器标志。这就是 C#“checked”块所做的。问题是 Java 没有提供它作为一种选择,而不是因为它超出了人类的智慧。 (2认同)

Joh*_*hnB 6

总和:检查b是否大于您可以存储在int中的最大值的差减去a的值.如果a和/或b可以是负数,则必须(i)注意不要为差异检查获得溢出并且(ii)对最小值执行类似的检查.

产品:这更难.我将整数分成两个半长整数(即如果int是32位,使用位掩码和移位将其分成两个16位数).然后进行乘法运算,然后查看结果是否适合32位.

在你不想简单地接受long临时结果的条件下的一切.