返回需要多少项才能输入精度等级,例如0.001,以达到PI值的指定精度范围内?

时间:2015-10-24 22:40:07

标签: java pi

问题: 以交互方式输入精度等级,例如.001,然后报告每个估算值必须达到指定精度范围内的数量。 PI。

我的解决方案: 当前结果不会终止。给出了PIEstimator类驱动程序。问题出在PIEstimates类中。我有一些具体问题:

如何在代码中计算Wallis PILeibniz PI?为瓦利斯计算每个算术的方法是:

pi / 4 =(2/3)(4/3)(4/5)(6/5)(6/7)( 8/7)(8/9)* ... 并为莱布尼兹:

pi / 4 =(1 - 1/3 + 1/5 - 1/7 + 1/9 ......)

到目前为止,执行此代码的当前逻辑是否正确?使用while循环检查相应的PI计算是否在限制范围内,并且内部的for循环继续运行,直到满足while要求。然后有一个计数返回循环重复的次数。

对于.001,例如,每个公式需要多少个术语才能达到3.14059 ..和3.14259之间的值......

import java.util.Scanner;

public class PiEstimator {

    public static void main(String[] args) {
    System.out.println("Wallis vs Leibnitz:");
    System.out.println("Terms needed to estimate pi");
    System.out.println("Enter precision sought");
    Scanner scan = new Scanner(System.in);
    double tolerance = scan.nextDouble();
    PiEstimates e = new PiEstimates(tolerance);
    System.out.println("Wallis: " + e.wallisEstimate());
    System.out.println("Leibnitz: " + e.leibnitzEstimate());
    }
}

public class PiEstimates {
    double n = 0.0;
    double upperLim = 0;
    double lowerLim = 0;

    public PiEstimates(double tolerance) {
        n = tolerance;
        upperLim = Math.PI+n;
        lowerLim = Math.PI-n;
    }

    public double wallisEstimate() {
        double wallisPi = 4;
        int count = 0;
        while(wallisPi > upperLim || wallisPi < lowerLim) {
            for (int i = 3; i <= n + 2; i += 2) {
                wallisPi = wallisPi * ((i - 1) / i) * ((i + 1) / i);
            }
            count++;
        }
        return count;
    }

    public double leibnitzEstimate() {
        int b = 1;
        double leibnizPi = 0;
        int count = 0;
        while(leibnizPi > upperLim || leibnizPi < lowerLim) {
            for (int i = 1; i < 1000; i += 2) {
                leibnizPi += (4/i - 4/i+2);
            }
            b = -b;
            count++;
        }
        return count;
    }
}

3 个答案:

答案 0 :(得分:0)

wallisEstimate

中至少有一个错误
for (int i = 3; i <= n + 2; i += 2) {

应该是count而不是n

for (int i = 3; i <= count + 2; i += 2) {

......但是算法仍然是错误的。这会更好:

public double wallisEstimate() {
    double wallisPi = 4;
    int count = 0;
    int i = 3;
    while(wallisPi > upperLim || wallisPi < lowerLim) {
        wallisPi = wallisPi * ((i - 1) / i) * ((i + 1) / i);
        count++;
        i += 2;
    }
    return count;
}

同样,对于莱布尼兹函数:

public double leibnitzEstimate() {
    double leibnizPi = 0;
    int count = 0;
    int i = 1;
    while(leibnizPi > upperLim || leibnizPi < lowerLim) {
        leibnizPi += (4/i - 4/i+2);
        count++;
        i += 4;
    }
    return count;
}

答案 1 :(得分:0)

对于Leibnitz,我认为内循环应该只运行count次:

for (int i = 1; i < count; i += 2) {
            leibnizPi += (4/i - 4/i+2);
        }

如果它每次运行1000次,你就不知道pi何时在范围内。

答案 2 :(得分:0)

如果while循环没有终止,那么他们就不会接近PI。

Wallis: pi/4 = (2/3)(4/3)(4/5)(6/5)(6/7)(8/7)(8/9)*...

while循环将重新启动i = 3的for循环,这将继续添加相同的术语序列,而不是继续使用模式。

这里是基于术语模式的替代解决方案草案(没有双关语意)。 如你所见,除了2之外,分子重复。除数重复,但偏离分子:它们以交替的方式递增。

通过这种方式,您可以实际计算每个单独的术语,而不是它们的对。

public double wallisEstimate() {
    double wallisPi = 1; 
    int count = 0;
    double numerator = 2;
    double divisor = 3;
    while(wallisPi > upperLim || wallisPi < lowerLim) {
        wallisPi *= numerator / divisor;
        if ( count++ & 1 == 0 )
            numerator+=2;
        else
            divisor+=2;
    }
    return count;
}

还有一项更改要做,那就是upperLimlowerLim的初始化。该算法接近PI/2,因此:

    upperLim = (Math.PI + tolerance)/2;
    lowerLim = (Math.PI - tolerance)/2;

莱布尼兹: pi/4 = (1 - 1/3 + 1/5 - 1/7 + 1/9 ...)

这里for循环也是不需要的:最多,你将一次计算2000个术语的增量。

如果您这样写,模式就会变得明显:

  

1/1 - 1/3 + 1/5 - 1/7 ......

每下一个任期的除数递增2。

public double leibnitzEstimate() {
    double leibnizPi = 0;
    int divisor = 1;
    int count = 0;
    while(leibnizPi > upperLim || leibnizPi < lowerLim) {
        leibnizPi +=  1.0 / divisor;
        divisor = -( divisor + 2 );  
        count++;
    }
    return count;
}

leibnizPi的更新也可以这样写:

        leibnizPi +=  sign * 1.0 / divisor;
        divisor += 2;
        sign = -sign;

更清楚,需要多一个变量和一个指令。

此处必须更新upperLimlowerLim:算法接近PI / 4(与Leibniz不同!),所以:

    upperLim = (Math.PI + tolerance)/4;
    lowerLim = (Math.PI - tolerance)/4;