我看到一些将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类型有何不同?
答案 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 complement和integer 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。最终结果将为负