我怎样才能检查在Java中乘以两个数字是否会导致溢出?
我想处理将两个数字相乘在一起导致溢出的特殊情况。 代码看起来像这样:
int a = 20; long b = 30; // if a or b are big enough, this result will silently overflow long c = a * b;
这是一个简化的版本。 在真正的程序中, a
和b
在运行时从别处获得。 我想要达到的是这样的:
long c; if (a * b will overflow) { c = Long.MAX_VALUE; } else { c = a * b; }
你如何build议我最好的代码呢?
更新: a
和b
在我的场景中总是非负的。
Java 8对于整数和长整数有Math.multiplyExact
, Math.addExact
等。 这些在溢出时抛出未经检查的ArithmeticException
。
如果a
和b
都是正数,那么你可以使用:
if (a != 0 && b > Long.MAX_VALUE / a) { // Overflow }
如果你需要处理正面和负面的数字,那么它更复杂:
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 }
这里有一个我鞭打检查这个,假装溢出发生在-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
有一些Java库提供安全的算术运算,检查长时间溢出/下溢。 例如,Guava的LongMath.checkedMultiply(int a,int b)返回a
和b
的乘积,前提是它不溢出,如果a * b
在带符号的long
算术中溢出则抛出ArithmeticException
。
你可以使用java.math.BigInteger来检查结果的大小(没有testing过代码):
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() }