找到pi - 使用Machin的公式。不同的迭代给出相同的结果

时间:2015-11-11 17:59:47

标签: c++ visual-studio pi

我写了一些程序来找到pi,这是最先进的。我使用了Machin的公式pi/4 = 4(arc-tan(1/5)) - (arc-tan(1/239))

问题在于,无论我做多次迭代,我都得到相同的结果,而我似乎无法理解为什么。

#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <math.h>
using namespace std;

double arctan_series(int x, double y) // x is the # of iterations while y     is the number
{
    double pi = y;
    double temp_Pi;
    for (int i = 1, j = 3; i < x; i++, j += 2) 
    {
        temp_Pi = pow(y, j) / j; //the actual value of the iteration
        if (i % 2 != 0)     // for every odd iteration that subtracts
        {
            pi -= temp_Pi;
        }
        else    // for every even iteration that adds
        {
            pi += temp_Pi;
        }
    }
    pi = pi * 4;
    return pi;
}

double calculations(int x) // x is the # of iterations
{
    double value_1, value_2, answer;
    value_1 = arctan_series(x, 0.2);
    value_2 = arctan_series(x, 1.0 / 239.0);
    answer = (4 * value_1) - (value_2);
    return answer;
}

int main() 
{
    double pi;
    int iteration_num;
    cout << "Enter the number of iterations: ";
    cin >> iteration_num;
    pi = calculations(iteration_num);
    cout << "Pi has the value of: " << setprecision(100) << fixed << pi     << endl;
    return 0;

}

3 个答案:

答案 0 :(得分:0)

这种方法收敛很快。如果您先从最小的数字开始,您将获得更高的准确性。从5 ^ 23> 2 ^ 53(双尾数的尾数中的位数),可能最大迭代次数为12次(13次赢得任何差异)。从较小的数字开始,您将获得更高的准确性。更改的行有注释:

double arctan_series(int x, double y)
{
    double pi = y;
    double temp_Pi;
    for (int i = 1, j = x*2-1; i < x; i++, j -= 2) // changed this line
    {
        temp_Pi = pow(y, j) / j;
        if ((j & 2) != 0)    // changed this line
        {
            pi -= temp_Pi;
        }
        else
        {
            pi += temp_Pi;
        }
    }
    pi = pi * 4;
    return pi;
}

对于双打,设置精度没有意义&gt; 18。

如果你想要一个需要更多迭代收敛的替代公式,使用pi / 4 = arc-tan(1/2)+ arc-tan(1/3),这将需要大约24次迭代。

答案 1 :(得分:0)

我无法重现您的问题,但这里有一些清理过的代码,其中包含一些C ++ 11习语和更好的变量名称。

#include <iostream>
#include <iomanip>
#include <math.h>

using namespace std;

// double arctan_series(int x, double y) // x is the # of iterations while y     is the number
// then why not name the parameters accoringly? In math we usually use x for the parameter.
// prefer C++11 and the auto notation wherever possible
auto arctan_series(int iterations, double x) -> double
{
    // note, that we don't need any temporaries here.

    // note, that this loop will never run, when iterations = 1
    // is that really what was intended?
    for (int i = 1, j = 3; i < iterations; i++, j += 2) 
    {
        // declare variables as late as possible and always initialize them
        auto t = pow(x, j) / j;
        // in such simple cases I prefer ?: over if-else. Your milage may vary
        x += (i % 2 != 0) ? -t : t;
    }
    return x * 4;
}

// double calculations(int x) // x is the # of iterations
// then why not name the parameter accordingly
// BTW rename the function to what it is supposed to do
auto approximate_pi(int iterations) -> double
{
    // we don't need all of these temporaries. Just write one expression.
    return 4 * arctan_series(iterations, 0.2) - arctan_series(iterations, 1.0 / 239.0);
}

auto main(int, char**) -> int
{
    cout << "Enter the number of iterations: ";
    // in C++ you should declare variables as late as possible
    // and always initialize them.
    int iteration_num = 0;
    cin >> iteration_num;

    cout << "Pi has the value of: "
         << setprecision(100) << fixed
         << approximate_pi(iteration_num) << endl;
    return 0;
}

当您删除我的解释性注释时,您会看到,生成的代码更简洁,更易于阅读,因此更易于维护。

我试了一下:

Enter the number of iterations: 3
Pi has the value of: 3.1416210293250346197169164952356368303298950195312500000000000000000000000000000000000000000000000000

Enter the number of iterations: 2
Pi has the value of: 3.1405970293260603298790556436870247125625610351562500000000000000000000000000000000000000000000000000

Enter the number of iterations: 7
Pi has the value of: 3.1415926536235549981768144789384678006172180175781250000000000000000000000000000000000000000000000000

Enter the number of iterations: 42
Pi has the value of: 3.1415926535897940041763831686694175004959106445312500000000000000000000000000000000000000000000000000

如您所见,对于不同的迭代次数,我显然会得到不同的结果。

答案 2 :(得分:0)

如果有些人感兴趣,这是另一种方式。循环计算函数的积分: sqrt(1-x²)

表示半径为1的半圆。然后我们将该区域乘以2。最后我们得到了圆圈的表面,即PI。

#include <iomanip>
#include <cmath>

#define f(x) sqrt(1-pow(x,2))

double integral(int a, int b, int p)
{
    double d=pow(10, -p), s=0;
    for (double x=a ; x+d<=b ; x+=d)
    {
        s+=f(x)+f(x+d);
    }
    s*=d/2.0;
    return s;
}

int main()
{
    cout << "PI=" << setprecision (9) << 2.0*integral(-1,1,6) << endl;
}