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

Ste*_*eod 94 java math overflow long-integer

我想处理两个数字相乘导致溢出的特殊情况.代码看起来像这样:

int a = 20;
long b = 30;

// if a or b are big enough, this result will silently overflow
long c = a * b;
Run Code Online (Sandbox Code Playgroud)

这是一个简化版本.在真正的程序中,ab在运行时在其他地方采购.我想要实现的是这样的:

long c;
if (a * b will overflow) {
    c = Long.MAX_VALUE;
} else {
    c = a * b;
}
Run Code Online (Sandbox Code Playgroud)

您如何建议我最好编码?

更新:a而且b总是在我的场景下非负.

bco*_*lan 83

对于int和long Math.multiplyExact,Java 8 Math.addExact等等.这些ArithmeticException在溢出时不受控制.


Joh*_*ica 59

如果a并且b都是肯定的那么你可以使用:

if (a != 0 && b > Long.MAX_VALUE / a) {
    // Overflow
}
Run Code Online (Sandbox Code Playgroud)

如果你需要处理正数和负数,那么它就更复杂了:

long maximum = Long.signum(a) == Long.signum(b) ? Long.MAX_VALUE : Long.MIN_VALUE;

if (a != 0 && (b > 0 && b > maximum / a ||
               b < 0 && b < maximum / a))
{
    // Overflow
}
Run Code Online (Sandbox Code Playgroud)

这是一个小桌子我掀起来检查这个,假装溢出发生在-10或+10:

a =  5   b =  2     2 >  10 /  5
a =  2   b =  5     5 >  10 /  2
a = -5   b =  2     2 > -10 / -5
a = -2   b =  5     5 > -10 / -2
a =  5   b = -2    -2 < -10 /  5
a =  2   b = -5    -5 < -10 /  2
a = -5   b = -2    -2 <  10 / -5
a = -2   b = -5    -5 <  10 / -2
Run Code Online (Sandbox Code Playgroud)

  • 我认为这可能会失败一个案例:a = -1和b = 10.最大/表达式导致Integer.MIN_VALUE并且当不存在时检测到溢出 (3认同)

rep*_*mer 17

有些Java库提供安全的算术运算,可检查长溢出/下溢.例如,番石榴的LongMath.checkedMultiply(长,长二)返回的产品ab,只要它不溢出,并抛出ArithmeticException,如果a * b在签订溢出long运算.

  • 这是最好的答案 - 使用一个库,该库由真正了解Java机器算法的人实现,并且已经过很多人的测试.不要试图自己编写或使用其他答案中发布的任何半生不熟的未经测试的代码! (4认同)
  • @Rich我是说包含巨大的库,所以您可以使用一个函数是一个坏主意。 (2认同)

Ulf*_*ack 6

您可以使用java.math.BigInteger来检查结果的大小(尚未测试代码):

BigInteger bigC = BigInteger.valueOf(a) * multiply(BigInteger.valueOf(b));
if(bigC.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
  c = Long.MAX_VALUE;
} else {
  c = bigC.longValue()
}
Run Code Online (Sandbox Code Playgroud)

  • 我觉得这个解决方案很慢 (7认同)
  • 我不确定你可以在BigInteger中使用'>'运算符.应该使用compareTo方法. (2认同)

Hig*_*ark 5

使用对数检查结果的大小.


Nar*_*ren 5

这是我能想到的最简单的方法

int a = 20;
long b = 30;
long c = a * b;

if(c / b == a) {
   // Everything fine.....no overflow
} else {
   // Overflow case, because in case of overflow "c/b" can't equal "a"
}
Run Code Online (Sandbox Code Playgroud)