Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Java中检查两个数字相乘是否会导致溢出?_Java_Math_Long Integer_Integer Overflow - Fatal编程技术网

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

如何在Java中检查两个数字相乘是否会导致溢出?,java,math,long-integer,integer-overflow,Java,Math,Long Integer,Integer Overflow,我想处理两个数字相乘导致溢出的特殊情况。代码如下所示: int a = 20; long b = 30; // if a or b are big enough, this result will silently overflow long c = a * b; long c; if (a * b will overflow) { c = Long.MAX_VALUE; } else { c = a * b; } 这是一个简化的版本。在实际程序中,a和b在运行时从别处获取

我想处理两个数字相乘导致溢出的特殊情况。代码如下所示:

int a = 20;
long b = 30;

// if a or b are big enough, this result will silently overflow
long c = a * b;
long c;
if (a * b will overflow) {
    c = Long.MAX_VALUE;
} else {
    c = a * b;
}
这是一个简化的版本。在实际程序中,
a
b
在运行时从别处获取。我想要实现的是这样的目标:

int a = 20;
long b = 30;

// if a or b are big enough, this result will silently overflow
long c = a * b;
long c;
if (a * b will overflow) {
    c = Long.MAX_VALUE;
} else {
    c = a * b;
}
您建议我如何编写此代码

更新:
a
b
在我的场景中始终是非负的。

可能:

if(b!= 0 && a * b / b != a) //overflow
不确定这个“解决方案”

编辑:添加了b!=0


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

您可以改用java.math.biginger并检查结果的大小(尚未测试代码):


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

Java是否有类似int.MaxValue的内容?如果是,请尝试

if (b != 0 && Math.abs(a) > Math.abs(Long.MAX_VALUE / b))
{
 // it will overflow
}

编辑:查看有问题的Long.MAX_值

如果
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
}
long max=long.signum(a)==long.signum(b)?Long.MAX\u值:Long.MIN\u值;
如果(a!=0&&(b>0&&b>最大值)/a||
b<0&&b
这里有一张小桌子,我用它来检查,假装溢出发生在-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
a=5b=22>10/5
a=2 b=5>10/2
a=-5B=22>-10/-5
a=-2b=55>-10/-2
a=5 b=-2-2<-10/5
a=2 b=-5-5<-10/2
a=-5b=-2-2<10/-5
a=-2b=-5-5<10/-2

我不知道为什么没有人在寻找这样的解决方案:

if (Long.MAX_VALUE/a > b) {
     // overflows
} 

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

也许这会帮助您:

/**
 * @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;
    }
}
从jruby偷来的

    long result = a * b;
    if (a != 0 && result / a != b) {
       // overflow
    }
更新:此代码很短,运行良好;但是,对于a=-1,b=Long.MIN_值,它会失败

一个可能的增强:

long result = a * b;
if( (Math.signum(a) * Math.signum(b) != Math.signum(result)) || 
    (a != 0L && result / a != b)) {
    // overflow
}
注意,这将捕获一些没有任何除法的溢出。

c/c++(long*long):

java(int*int,很抱歉,我在java中没有找到int64):

1.以大字体保存结果(int*int将结果放入long,long*long放入int64)


2.cmp结果>>位和结果>>(位-1)

有一些Java库提供安全的算术运算,用于检查长溢出/下溢。例如,Guava's返回
a
b
的乘积,如果
a*b
在有符号
long
算术中溢出,则返回
a
b
,并抛出
算术异常
。它们在溢出时抛出未经检查的
算术异常。

我想在John Kugelman的答案的基础上构建它,而不需要直接编辑它来替换它。它适用于他的测试用例(
MIN_VALUE=-10
MAX_VALUE=10
),因为
MIN_VALUE==-MAX_VALUE
的对称性,而不是两个补码整数的对称性。实际上,
MIN\u VALUE==-MAX\u VALUE-1

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_值
MAX_值
时,当
a==-1
b==
任何其他值(凯尔首先提出的点)时,约翰·库格曼的答案会产生溢出情况。这里有一个解决方法:

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
}
long max=long.signum(a)==long.signum(b)?Long.MAX\u值:Long.MIN\u值;
if((a=-1&&b==Long.MIN\u值)||
(a!=-1&&a!=0&&((b>0&&b>最大值/a)||
(b<0&&b

它不是任何
MIN_值
MAX_值
的通用解决方案,但它是Java的
Long
Integer
以及
a
b

的任何值的通用解决方案,正如已经指出的那样,Java 8具有Math.xxxExact方法,可以在溢出时抛出异常

如果您的项目没有使用Java8,您仍然可以“借用”它们非常紧凑的实现

下面是JDK源代码存储库中这些实现的一些链接,不能保证这些实现是否有效,但无论如何,您应该能够下载JDK源代码,并查看它们在
java.lang.Math
类中如何发挥作用

Math.multiplyExact(long,long)

Math.addExact(long,long)

等等等等


更新:切换到第三方网站的无效链接到开放JDK的Mercurial存储库的链接。

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

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"
}

我不回答,但看看Java代码,它很简单。在JDK8中,它转换为长操作,并将结果向下转换为int值,并与长结果进行比较,以查看值是否已更改。下面的代码解释得比我好

@HotSpotIntrinsicCandidate
public static int multiplyExact(int x, int y) {
    long r = (long)x * (long)y;
    if ((int)r != r) {
        throw new ArithmeticException("integer overflow");
    }
    return (int)r;
}

不过,我觉得这个解决方案可能是最好的办法。我假设这是一个数值应用程序,这就是为什么我不立即推荐它的原因,但这可能是解决这个问题的最佳方法。我不确定您是否可以将“>”运算符与BigInteger一起使用。应该使用compareTo方法。更改为compareTo,速度可能重要,也可能不重要,这取决于使用代码的环境。您的意思是:
ceil(log(a))+ceil(log(b))>log(Long.MAX)
?我检查了它。对于较小的值,它比BigInteger快20%,对于接近MAX的值,它几乎相同(快5%)。Yossarian的代码是最快的(比BigInteger快95%和75%)。我怀疑它在某些情况下可能会失败。请记住,整数日志实际上只是计算前导零的数量,您可以优化一些常见情况(例如,如果((a | b)&0xffffffff00000000L)==0)您知道您是安全的)。另一方面,除非你能
@HotSpotIntrinsicCandidate
public static int multiplyExact(int x, int y) {
    long r = (long)x * (long)y;
    if ((int)r != r) {
        throw new ArithmeticException("integer overflow");
    }
    return (int)r;
}