[英]Why does counting to 2^24 execute quickly, but counting to 2^25 take much longer?
I was fiddling around making infinite loops to test some other code/my understanding, and came across this strange behaviour. 我正在摆弄无限循环来测试其他代码/我的理解,并遇到了这种奇怪的行为。 In the program below, counting from 0 to 2^24 takes <100ms on my machine, but counting to 2^25 takes orders of magnitude more time (at time of writing, it's still executing).
在下面的程序中,从0到2 ^ 24的计数在我的机器上花费<100ms,但是计数到2 ^ 25需要更多的时间(在写入时,它仍在执行)。
Why is this the case? 为什么会这样?
This was under Java 1.8.0_101, on a 64-bit copy of Windows 10. 这是在Windows 1.8的64位副本上的Java 1.8.0_101下。
TestClass.java TestClass.java
public class TestClass {
public static void main(String[] args) {
addFloats((float) Math.pow(2.0, 24.0));
addFloats((float) Math.pow(2.0, 25.0));
}
private static void addFloats(float number) {
float f = 0.0f;
long startTime = System.currentTimeMillis();
while(true) {
f += 1.0f;
if (f >= number) {
System.out.println(f);
System.out.println(number + " took " + (System.currentTimeMillis() - startTime) + " msecs");
break;
}
}
}
}
This is because float
s have a minimum precision that can be represented, which decreased as the float
's value becomes larger. 这是因为
float
s具有可以表示的最小精度,随着float
值变大而减小。 Somewhere between 2^24 and 2^25, adding one is no longer enough to change the value to the next largest representable number. 在2 ^ 24和2 ^ 25之间的某处,添加一个不再足以将值更改为下一个可表示的最大数字。 At that point, every time through the loop,
f
just keeps the same value, since f += 1.0f
no longer changes it. 此时,每次循环时,
f
只保持相同的值,因为f += 1.0f
不再改变它。
If you change your loop to this: 如果您将循环更改为:
while(true) {
float newF = f + 1.0f;
if(newF == f) System.out.println(newF);
f += 1.0f;
if (f >= number) {
System.out.println(f);
System.out.println(number + " took " + (System.currentTimeMillis() - startTime) + " msecs");
break;
}
}
You can see this happening. 你可以看到这种情况发生。 It seems as though it stops increasing as soon as
f
reaches 2^24. 一旦
f
达到2 ^ 24,它似乎就会停止增加。
The output of the above code will be an endless number of "1.6777216E7" if you run it with 2^25. 如果你用2 ^ 25运行它,上面代码的输出将是无穷无尽的“1.6777216E7”。
You can test this value by using the Math.nextAfter
function , which tells you the next representable value. 您可以使用
Math.nextAfter
函数测试此值,该函数告诉您下一个可表示的值。 If you try running this code: 如果您尝试运行此代码:
float value = (float)Math.pow(2.0, 24.0);
System.out.println(Math.nextAfter(value, Float.MAX_VALUE) - value);
you can see that the next representable value after 2^24 is 2^24 + 2. 你可以看到2 ^ 24之后的下一个可表示的值是2 ^ 24 + 2。
For an excellent breakdown of why this happens, and why it starts mattering where it does, see this answer 为了更好地解释为什么会发生这种情况,以及为什么它开始在何处发生,请参阅此答案
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.