我看到一些奇怪的行为与 Java 相乘整数。我正在做一些编码练习,并遇到了以下 fizz buzz 类型的练习。要求:给定一个整数,编写一个函数,找出小于给定整数的每一个 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 类型有什么不同之处使其能够正确执行?
让我们以 Integer
为例来研究一下。
Integer.MAX_VALUE
可以表示为 01111111111111111111111111111111
,这是一个 32
位长字符串(包括符号位)。现在,如果您碰巧将 1
添加到上述字符串,它会生成 10000000000000000000000000000000
,这与 Integer.MIN_VALUE
相同。这称为 Integer
的溢出。
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE));
// 1111111111111111111111111111111
根据 Integer#toBinaryString
:
The unsigned integer value is the argument plus 232 if the argument is negative; otherwise it is equal to the argument. This value is converted to a string of ASCII digits in binary (base 2) with no extra leading 0s.
这就是为什么您看不到符号位,但 Integer.MAX_VALUE
的实际值为 01111111111111111111111111111111
的原因。现在看看这段代码:
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE + 1));
// 10000000000000000000000000000000
System.out.println(Integer.toBinaryString(Integer.MIN_VALUE));
// 10000000000000000000000000000000
两个数字的输出是相同的。 Java 不能防止 Integer
溢出。应该由开发人员负责。那么这个问题的可能解决方案是什么?您可以使用其他数据类型,例如 long
或 BigInteger
.以下是您可能感兴趣的最大值:
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Long.MAX_VALUE); // 9223372036854775807
System.out.println(Double.MAX_VALUE); // 1.7976931348623157E308
System.out.println(Float.MAX_VALUE); // 3.4028235E38
一旦 Integer
达到 MAX_VALUE
,它就会开始溢出,最终会变成负值。