计算 C++ 中 π 的莱布尼茨求和的迭代次数

Counting iterations of the Leibniz summation for π in C++

我的任务是询问用户,与 pi 的实际值相比,他们希望求和迭代的精度为多少位小数。因此,当循环达到 3.14 时,小数点后 2 位将停止。我有一个完整的程序,但我不确定它是否真的按预期工作。我已经用计算器检查了小数点后 0 位和 1 位,它们似乎有效,但我不想假设它对所有小数都有效。此外,我的代码可能有点笨拙,因为我们仍在学习基础知识。我们只学习了循环和嵌套循环。如果有任何明显的错误或可以清理的部分,我将不胜感激。 编辑:我只需要让这项工作最多保留五位小数。这就是为什么我的 pi 值不精确的原因。很抱歉对于这个误会。

#include <iostream>
#include <cmath>
using namespace std;

int main() {

const double PI = 3.141592;
int n, sign = 1;
double sum = 0,test,m;

cout << "This program determines how many iterations of the infinite series   for\n"
        "pi is needed to get with 'n' decimal places of the true value of pi.\n"
        "How many decimal places of accuracy should there be?" << endl;
cin >> n;

double p = PI * pow(10.0, n);
p = static_cast<double>(static_cast<int>(p) / pow(10, n));
int counter = 0;
bool stop = false;

for (double i = 1;!stop;i = i+2) {
    sum = sum + (1.0/ i) * sign;
    sign = -sign;
    counter++;
    test = (4 * sum) * pow(10.0,n);
    test = static_cast<double>(static_cast<int>(test) / pow(10, n));

        if (test == p)
            stop = true;
}
cout << "The series was iterated " << counter<< " times and reached the value of pi\nwithin "<< n << " decimal places." << endl;
return 0;
}

你的程序永远不会终止,因为 test==p 永远不会为真。这是两个计算方式不同的双精度数字之间的比较。由于舍入误差,它们将不相同,即使您 运行 无限次迭代,并且您的数学是正确的(现在不是,因为 PI 的值在你的程序中是不准确的)。

为了帮助您弄清楚发生了什么,在每次迭代中打印 test 的值,以及 testpi 之间的距离,如下所示:

#include<iostream>
using namespace std;

void main() {
    double pi = atan(1.0) * 4; // Make sure you have a precise value of PI
    double sign = 1.0, sum = 0.0;
    for (int i = 1; i < 1000; i += 2) {
        sum = sum + (1.0 / i) * sign;
        sign = -sign;
        double test = 4 * sum;
        cout << test << " " << fabs(test - pi) << "\n";
    }
}

确保程序运行良好后,最终将停止条件更改为基于 testpi 之间的距离。

for (int i=1; fabs(test-pi)>epsilon; i+=2)

莱布尼茨求和的一个问题是它的收敛速度极低,因为它表现出次线性收敛。在您的程序中,您还将计算出的 π 估计值与给定值(6 位近似值)进行比较,而求和的重点应该是找出正确的数字。

如果所需数字在迭代之间没有变化,您可以稍微修改代码以终止计算(我还添加了最大迭代次数检查)。请记住,您使用的 double 不是无限精度数字,舍入误差迟早会影响计算。事实上,这段代码的真正限制是它需要的迭代次数(2,428,700,925 获得3.141592653)。

#include <iostream>
#include <cmath>
#include <iomanip>

using std::cout;

// this will take a long long time...
const unsigned long long int MAX_ITER = 100000000000;

int main() {

    int n;

    cout << "This program determines how many iterations of the infinite series for\n"
            "pi is needed to get with 'n' decimal places of the true value of pi.\n"
            "How many decimal places of accuracy should there be?\n";
    std::cin >> n;

    // precalculate some values
    double factor = pow(10.0,n);
    double inv_factor = 1.0 / factor;
    double quad_factor = 4.0 * factor;

    long long int test = 0, old_test = 0, sign = 1;
    unsigned long long int count = 0;
    double sum = 0;

    for ( long long int i = 1; count < MAX_ITER; i += 2 ) {
        sum += 1.0 / (i * sign);
        sign = -sign;
        old_test = test;
        test = static_cast<long long int>(sum * quad_factor);
        ++count;
        // perform the test on integer values
        if ( test == old_test ) {
            cout << "Reached the value of Pi within "<< n << " decimal places.\n";
            break;          
        }
    } 

    double pi_leibniz = static_cast<double>(inv_factor * test);
    cout << "Pi = " << std::setprecision(n+1) << pi_leibniz << '\n';    
    cout << "The series was iterated " << count << " times\n";

    return 0;
}

我在这table总结了几次运行的结果:

digits        Pi           iterations
---------------------------------------
 0        3                           8
 1        3.1                        26
 2        3.14                      628
 3        3.141                   2,455
 4        3.1415                136,121
 5        3.14159               376,848
 6        3.141592            2,886,751
 7        3.1415926          21,547,007
 8        3.14159265        278,609,764
 9        3.141592653     2,428,700,925
10        3.1415926535   87,312,058,383