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

finding pi - using Machin's formula. Different iterations are giving same result

我写了几个程序来寻找圆周率,这个是最先进的。我使用了 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;

}

那个方法收敛的很快。如果您首先从最小的数字开始,您将获得更高的准确性。由于 5^23 > 2^53(double 的尾数中的位数),最大迭代次数可能是 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;
}

对于双打,设置精度 > 18 没有意义。

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

我无法重现你的问题,但这里有一些经过清理的代码,其中包含一些 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

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

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

表示半径为1的半圆,然后我们用面积乘以2。最后我们得到了圆的表面,也就是圆周率。

#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;
}