Java:为什么将大正数相乘会导致负数结果?

时间:2019-03-24 11:09:13

标签: java math types

我看到一些将Java与整数相乘的奇怪行为。我正在做一些编码练习,然后进行了以下嘶嘶声类型的练习。要求:给定一个整数,编写一个函数,该函数查找小于给定整数的3的每个倍数的乘积,为5的任何倍数。例如,给定17,我们想返回12 * 9 * 6 * 3(= 1944)。我写了以下内容:

public int findProduct(int limit) { 
    int product = 1;
    for(int n = 3; n < limit; n = n + 3) {
        if (n % 5 != 0) {
            product = product * n;
        }
    }
    return product;
}

这对于少量数字也很好。但是在测试中,我发现一旦达到33以上,返回值就会消失。例如,如果我调用限制为36的函数,则它将返回-1.466221696E9。这就是我感到困惑的地方。我乘以正数整数,结果是负数。

但是,我发现如果声明一个double值,它似乎总是会返回正确的结果。

public double findProduct(int limit) { 
    double product = 1;
    for(int n = 3; n < limit; n = n + 3) {
        if (n % 5 != 0) {
            product = product * n;
        }
    }
    return product;
}

我的问题是:为什么整数会发生这种情况?使double类型正确执行的double类型有何不同?

4 个答案:

答案 0 :(得分:5)

发生这种情况是因为MAX_VALUE的{​​{1}}是int。您也可以将2147483647替换为int,以获得预期的结果。

long

一旦System.out.println(Integer.MAX_VALUE); // 2147483647 System.out.println(Long.MAX_VALUE); // 9223372036854775807 System.out.println(Double.MAX_VALUE); // 1.7976931348623157E308 到达Integer,它将开始溢出并且最终将变为负值。

答案 1 :(得分:2)

这称为整数溢出。本质上,您的数字对于存储解决方案所在的数据类型而言太大。发生这种情况时,由于二进制补码,数字会环绕为负数。 double是较大的数据类型,但是如果您将数据放大得足够大,它也会变成负数。

请参阅two's complementinteger overflow上的这些文章。他们会详细解释。

答案 2 :(得分:2)

如果您想完全避免整数溢出问题,请尝试使用BigInteger:
https://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html
这允许任意长度的整数。

(实际上,通过查看BigInteger的源代码,似乎有一个最大的大小,即存储了BigInteger的int []:

Integer.MAX_VALUE / Integer.SIZE + 1

比任何人都想要的大得多!)

答案 3 :(得分:1)

超出Double.MAX_VALUE的范围,这就是为什么结果变为负数

示例:

为四位二进制数据。

00001此处保留了符号位的最左位,[0表示+,1表示-],其余4位用于存储值。所以00001 binary =十进制+1

因此,对于4位,我们最多可以写入15个十进制值。

现在,如果我想写16,则溢出值范围。

因此,如果我将十进制的16转换为二进制数据,它将是10000,所以符号位现在是1。最终结果将为负