简体   繁体   English

为什么计数到2 ^ 24会很快执行,但计算到2 ^ 25需要更长的时间?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM