for循环中

时间:2017-04-13 13:22:53

标签: java loops numbers precision

我写了这个小程序来计算pi。

在玩代码并试图找到最准确的结果时,我发现我的计算机无法计算结果。它可以在几秒钟内完成 33554430 重复,但是如果我将for循环增加到 33554431 它没有输出任何东西。

33554430 一个特殊号码?

public class CalculatePi{
    public static void main(String[] args){
        float pi=0;
        int sign=1;
        for(float i=1; i <= 33554430; i+=2){
            pi += (sign*(1.0/i));
            sign*= -1;
        }
        pi *= 4;
        System.out.println(pi);
     }

}

4 个答案:

答案 0 :(得分:2)

你正在获得无限循环,因为在比较i <= 33554431期间,int33554431promoted to a float值,这对于浮点数来说太“精确”了等于33554432。 然后,当您尝试将值增加+2时,float只是不够精确,无法从值33554432增加。为了说明我的观点:

float f = 33554432;
System.out.println(f); //33554432
f += 2;
System.out.println(f); //33554432

因此,f值不会因精度限制而增加。如果你增加它,比如说11,你会得到33554444(而不是33554443),因为这是最接近该精度的数字。

  

33554430 一个特殊号码?

排序,而不是33554430,而是33554432.浮点数的第一个“特殊数字”是16777217,这是第一个不能表示为float的正整数(等于16777216作为浮动)。因此,如果您将i变量增加1,这就是您要坚持的数字。现在,由于您按2递增,因此您遇到的数字为16777216 * 2 = 33554432

答案 1 :(得分:1)

public class CalculatePi{
    public static void main(String[] args){
        float pi=0;
        int sign=1;
        for(float i=1; i <= 33554431; i+=2){
            pi += (sign*(1.0/i));
            sign*= -1;
        if( i > 33554410) System.out.println(i);
        }
        pi *= 4;
        System.out.println(pi);

        System.out.println((float)33554431);
        System.out.println((float)33554432);
        System.out.println((float)33554434);
     }

}

在for循环中将float与int进行比较。当您将33554431(它的int值)转换为float时,您将获得3.3554432E7

这是关于准确性,精确度。当你跑:

System.out.println((float)33554431);  // -> 3.3554432E7
System.out.println((float)33554432);  // -> 3.3554432E7
System.out.println((float)33554434);  // -> 3.3554432E7

所有3个打印3.3554432E7,这意味着当你将浮点值33554432增加2时,你得到3.3554432E7,这个值完全相同,你的循环将永远运行。

答案 2 :(得分:0)

此版本适用于两者。它是浮动循环变量导致问题:

public static class Extensions
{
    public static string ReadTextResource(this Assembly asm, string resName)
    {
        string text;
        using (Stream strm = asm.GetManifestResourceStream(resName))
        {
            using (StreamReader sr = new StreamReader(strm))
            {
                text = sr.ReadToEnd();
            }
        }
        return text;
    }
}

可能这是issue

  

任何浮点值集的有限非零值都可以   以s·m·2(e-N + 1)的形式表示,其中s是+1或-1,m是   小于2N的正整数,e是Emin =之间的整数    - (2K-1-2)和Emax = 2K-1-1,包括端点,其中N和K是取决于设定值的参数。

答案 3 :(得分:0)

你的循环每次增加2。

2 * 33554430 = 67108860

2 ^ 26 = 67108864

也许Java在32位系统中存储浮点数,尾数为26位,指数为6位?