2

我正在做另一个 C++ 练习。我必须从无限级数中计算 pi 的值:

pi=4 - 4/3 + 4/5 - 4/7 + 4/9 -4/11+ 。. .

该程序必须在本系列的前 1,000 个术语之后打印 pi 的近似值。这是我的代码:

#include <iostream>
using namespace std;

int main()
{
    double pi=0.0;
    int counter=1;

    for (int i=1;;i+=2)//infinite loop, should "break" when pi=3.14159
    {
        double a=4.0;
        double b=0.0;

        b=a/static_cast<double>(i);

        if(counter%2==0)
            pi-=b;
        else
            pi+=b;

        if(i%1000==0)//should print pi value after 1000 terms,but it doesn't  
            cout<<pi<<endl;

        if(pi==3.14159)//this if statement doesn't work as well
            break;

        counter++;
    }

    return 0;
}

它编译时没有错误和警告,但执行后只出现空的控制台窗口。如果我删除行“if(i%1000==0)”,我可以看到它运行并打印每个 pi 值,但它不会停止,这意味着第二个 if 语句也不起作用。我不确定还能做什么。我假设这可能是一个简单的逻辑错误。

4

10 回答 10

20

好吧,i % 1000 永远不会 = 0,因为您的计数器从 i = 1 开始运行,然后以 2 为增量。因此,i 总是奇数,并且永远不会是 1000 的倍数。

它永远不会终止的原因是该算法不能准确地收敛到 3.14157 - 无论是低于还是高于近似值,它都会有更高的精度。你想说“当在 3.14157 的给定增量内时”,所以写

if (fabs(pi - 3.14157) < 0.001)
  break

或类似的东西,无论您想在停止之前获得“关闭”。

于 2009-09-25T20:01:40.657 回答
7

由于您从 1 开始 i 并以 2 递增,因此 i 始终是奇数,因此 i % 1000 永远不会为 0。

于 2009-09-25T20:00:48.100 回答
4

你有不止一个问题:

A. i%1000==0 永远不会是真的,因为你只迭代奇数。

B. pi==3.14159 :你不能像这样比较双精度值,因为浮点数的表示方式(你可以在另一个问题中阅读它)。为了使其工作,您应该以另一种方式比较这些值 - 一种方法是将它们彼此相减并检查绝对结果是否低于 0.0000001。

于 2009-09-25T20:08:43.800 回答
2
  1. 您有浮点精度问题。试试if(abs(pi - 3.14159) < 0.000005)
  2. i%1000永远不会为 0,因为i总是奇数。
于 2009-09-25T20:01:45.623 回答
2

不应该是:

if (counter%1000==0)
于 2009-09-25T20:02:52.573 回答
2
  1. i 从 1 开始,然后以 2 递增。因此 i 始终是奇数,永远不会是 1000 的倍数,这就是为什么 if (i % 1000 == 0) 永远不会通过的原因。

  2. 由于浮点精度问题,直接比较浮点数不起作用。您将需要比较这些值之间的差异是否足够接近。

于 2009-09-25T20:03:26.347 回答
2

pi=4 - 4/3 + 4/5 – 4/7 + 4/9 -4/11 + ...

概括

pi = Σ i =0 (-1) i 4 / (2 i +1)

这使我们对每个术语都有更清晰的方法;第i项由下式给出:

double term = pow(-1,i%2) * 4 / (2*i+1);

其中i =0,1,2,...,N

所以,我们的循环可以相当简单,给定一些迭代次数 N

int N=2000;
double pi=0;
for(int i=0; i<N; i++)
{
    double term = pow(-1,i%2) * 4 / (2*(double)i+1);
    pi += term;
    cout << i << "\t" << pi <<endl;
}

您最初的问题是“程序必须在本系列的前 1,000 个术语之后打印 pi 的近似值”。这并不意味着需要检查是否已达到 3.14159,因此我没有在此处包含此内容。pow(-1,i%2)调用只是为了避免语句(很慢)并防止大iif任何并发症。

请注意,经过多次迭代后, pi 的大小与校正项的大小(例如 -4/25)之间的差异将非常小,以至于超出 a 的精度double,因此您需要更高的精度类型来处理它。

于 2009-09-27T17:04:53.310 回答
0

默认情况下,abs 使用用于 int 的 abs 宏。对于双打,使用 cmath 库。

#include <iostream>
#include <cmath>

int main()
{
    double pi=0.0;

    double a=4.0;
    int i = 1; 

    for (i=1;;i+=2)
    {

        pi += (1 - 2 * ((i/2)%2)) * a/static_cast<double>(i);          

        if( std::abs(pi - 3.14159) < 0.000001 )
              break;

        if (i > 2000) //1k iterations
              break;
    }

    std::cout<<pi<<std::endl;

    return 0;
}
于 2009-09-25T23:50:18.827 回答
0

这是更正后的代码。如果有人有类似的问题,我认为将来可能会有所帮助。

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
double pi=0.0;
int counter=1;

for (int i=1;;i+=2)
{
 double a=4.0;
 double b=0.0;

 b=a/static_cast<double>(i);

 if(counter%2==0)
  pi-=b;
 else
  pi+=b;

 if(counter%1000==0) 
  cout<<pi<<" "<<counter<<endl;


 if (fabs(pi - 3.14159) < 0.000001) 
  break;

 counter++;
}
cout<<pi;

 return 0;
}
于 2009-09-27T13:08:06.673 回答
0

这是一个更好的:

class pi_1000
{
public:
    double doLeibniz( int i ) // Leibniz famous formula for pi, source: Calculus II :)
    {
        return ( ( pow( -1, i ) ) * 4 ) / ( ( 2 * i ) + 1 );
    }

 void piCalc()
{
    double pi = 4;
    int i;

    cout << "\npi calculated each iteration from 1 to 1000\n"; //wording was a bit confusing.
                                                    //I wasn't sure which one is the right one: 0-1000 or each 1000th.
    for( i = 1; i < 1000; i++ )
    {
        pi = pi + doLeibniz( i );
        cout << fixed << setprecision( 5 ) << pi << "\t" << i + 1 << "\n";
    }

    pi = 4;
    cout << "\npi calculated each 1000th iteration from 1 to 20000\n";
    for( i = 1; i < 21000; i++ )
    {
        pi = pi + doLeibniz( i );
        if( ( ( i - 1 ) % 1000 )  == 0 )
            cout << fixed << setprecision( 5 ) << pi << "\t" << i - 1 << "\n";
    }

}
于 2013-09-28T22:13:26.920 回答