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

如何检查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;

}

您如何建议我最好编码?

更新:a和b在我的方案中始终是非负的。

14个解决方案

78 votes

对于int和long,Java 8有Math.multiplyExact,Math.addExact等。 这些在溢出时抛出未经检查的ArithmeticException。

bcoughlan answered 2019-08-26T05:16:03Z

59 votes

如果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

John Kugelman answered 2019-08-26T05:16:43Z

17 votes

有些Java库提供安全的算术运算,可检查长溢出/下溢。 例如,Guava的LongMath.checkedMultiply(long a,long b)返回a和b的乘积,前提是它不溢出,如果a * b在带符号的long算术中溢出,则抛出ArithmeticException。

reprogrammer answered 2019-08-26T05:17:12Z

6 votes

您可以使用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()

}

Ulf Lindback answered 2019-08-26T05:17:39Z

6 votes

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

High Performance Mark answered 2019-08-26T05:18:06Z

4 votes

Java有类似int.MaxValue的东西吗? 如果是,那就试试吧

if (b != 0 && Math.abs(a) > Math.abs(Long.MAX_VALUE / b))

{

// it will overflow

}

编辑:看到有问题的Long.MAX_VALUE

nothrow answered 2019-08-26T05:18:40Z

3 votes

从jruby偷来的

long result = a * b;

if (a != 0 && result / a != b) {

// overflow

}

更新:此代码简短,运行良好; 但是,它失败了a = -1,b = Long.MIN_VALUE。

一个可能的增强:

long result = a * b;

if( (Math.signum(a) * Math.signum(b) != Math.signum(result)) ||

(a != 0L && result / a != b)) {

// overflow

}

请注意,这将捕获一些溢出而不进行任何除法。

rogerdpack answered 2019-08-26T05:19:28Z

2 votes

我不确定为什么没有人在寻找解决方案:

if (Long.MAX_VALUE/a > b) {

// overflows

}

选择一个更大的两个数字。

fastcodejava answered 2019-08-26T05:20:01Z

2 votes

我希望以John Kugelman的答案为基础,而不是通过直接编辑来替换它。 它适用于他的测试用例(MIN_VALUE,MAX_VALUE),因为Long的对称性,这不是两个补码整数的情况。 实际上,Integer。

scala> (java.lang.Integer.MIN_VALUE, java.lang.Integer.MAX_VALUE)

res0: (Int, Int) = (-2147483648,2147483647)

scala> (java.lang.Long.MIN_VALUE, java.lang.Long.MAX_VALUE)

res1: (Long, Long) = (-9223372036854775808,9223372036854775807)

当应用于真实的MIN_VALUE和MAX_VALUE时,John Kugelman的答案会在Long和Integer的任何其他情况下产生溢出情况(由Kyle首先提出)。 以下是解决问题的方法:

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

if ((a == -1 && b == Long.MIN_VALUE) ||

(a != -1 && a != 0 && ((b > 0 && b > maximum / a) ||

(b < 0 && b < maximum / a))))

{

// Overflow

}

它不是任何MIN_VALUE和MAX_VALUE的通用解决方案,但它通用于Java的Long和Integer以及任何值a和b。

Jim Pivarski answered 2019-08-26T05:20:47Z

2 votes

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

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"

}

Naren answered 2019-08-26T05:21:16Z

1 votes

也许:

if(b!= 0 && a * b / b != a) //overflow

不确定这个&#34;解决方案&#34;。

编辑:添加b!= 0。

在你投票之前:a * b / b不会被优化。 这将是编译器错误。 我仍然没有看到可以掩盖溢出错误的情况。

Thomas Jung answered 2019-08-26T05:22:01Z

1 votes

也许这会对你有所帮助:

/**

* @throws ArithmeticException on integer overflow

*/

static long multiply(long a, long b) {

double c = (double) a * b;

long d = a * b;

if ((long) c != d) {

throw new ArithmeticException("int overflow");

} else {

return d;

}

}

dfa answered 2019-08-26T05:22:31Z

1 votes

正如已经指出的那样,Java 8具有Math.xxxExact方法,可以在溢出时抛出异常。

如果您没有将Java 8用于您的项目,您仍然可以&#34;借用&#34; 他们的实现非常紧凑。

以下是第三方网站上这些实现的一些链接,不保证这些实现是否保持有效,但无论如何您应该能够进入JDK源并看看他们如何在Math.addExact类中实现他们的魔力。

Math.addExact[http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/Math.java?av=f#882]

Math.addExact[http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/Math.java?av=f#805]

等等

StFS answered 2019-08-26T05:23:38Z

-1 votes

c / c ++(long * long):

const int64_ w = (int64_) a * (int64_) b;

if ((long) (w >> sizeof(long) * 8) != (long) w >> (sizeof(long) * 8 - 1))

// overflow

java(int * int,抱歉我在java中找不到int64):

const long w = (long) a * (long) b;

int bits = 32; // int is 32bits in java

if ( (int) (w >> bits) != (int) (w >> (bits - 1))) {

// overflow

}

1.将结果保存为大型(int * int将结果放入long,long * long放入int64)

2.cmp结果&gt;&gt; 位和结果&gt;&gt; (位 - 1)

xuan answered 2019-08-26T05:24:32Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值