Pergunta

eu estou fazendo outro C ++ exercício. Eu tenho que calcular o valor de pi da série infinita:

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

O programa deve imprimir o valor aproximado de pi após cada um dos primeiros 1000 termos desta série. Aqui está o meu código:

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

Ele compila sem erros e avisos, mas somente a janela do console vazia aparece após a execução. Se eu remover linha”if (% i 1000 == 0)”, eu posso ver ele correr e imprimir todos os valores pi, mas ele não parar, o que significa a segunda declaração se não quer trabalhar. Eu não sei mais o que fazer. Eu estou supondo que ele é provavelmente um erro de lógica simples.

Foi útil?

Solução

Bem, i% 1.000 jamais = 0, como seu contador vai de i = 1, então em incrementos de 2. Assim, i é sempre estranho, e nunca será um múltiplo de 1000.

A razão nunca termina é que o algoritmo não convergem para exatamente 3,14157 - vai ser uma precisão maior, quer sob ou sobre a aproximação. Você quer dizer "Quando dentro de um determinado delta de 3,14157", de modo write

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

ou algo semelhante, para no entanto "fechar" você quer começar antes de parar.

Outras dicas

Uma vez que você começar a i a 1 e incremento por 2, i é sempre um número ímpar, então i% 1000 nunca será 0.

Você tem mais do que um problema:

A. i% 1000 == 0 nunca será verdadeira porque você é a iteração apenas números ímpares.

B. pi == 3,14159: você não pode comparar valores double apenas como aquele porque a forma como números de ponto flutuante são representados (você pode ler sobre ele aqui em uma outra questão). em ordem para que ele funcione você deve comparar os valores de outra maneira - é uma maneira de subtrair-los entre si e verificar que o resultado absoluto é menor que 0.0000001

.
  1. você tem problemas de ponto flutuante de precisão. Tente if(abs(pi - 3.14159) < 0.000005).
  2. i%1000 nunca será 0 porque i é sempre estranho.

Não deveria ser:

if (counter%1000==0)
  1. i começa em 1 e, em seguida, incrementos de 2. Portanto i é sempre estranho e nunca será um múltiplo de 1000, razão pela qual se (% i 1000 == 0) nunca passa.

  2. Diretamente comparando carros alegóricos não funcionar, devido a questões de precisão flutuantes. Você vai precisar para comparar a diferença entre os valores é perto o suficiente.

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

Generalizar

pi = S i = 0 8 (-1) i 4 / (2 i 1)

O que nos dá uma abordagem mais limpo para cada termo; o i 'th prazo é dado por:

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

que i = 0,1,2, ..., N

Assim, o nosso laço pode ser bastante simples, dado algum número de iterações 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;
}

A sua pergunta original declarou: "O programa tem que imprimir o valor aproximado de pi após cada um dos primeiros 1000 termos desta série". Isto não implica qualquer necessidade de verificar se 3,14159 foi alcançado, então eu não ter incluído esta aqui. A chamada pow(-1,i%2) é apenas para declarações if evitar (que são lentos) e evitar quaisquer complicações com grande i .

Esteja ciente de que após um número de iterações, a diferença entre a magnitude do pi e a magnitude do termo corrigindo (dizem -4/25) será tão pequena que vai além da precisão de um double, para que precisaria tipos de precisão mais altos para lidar com isso.

Por abs padrão usa a macro abs que é para int. Para duplas, usar a biblioteca 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;
}

Aqui está o código corrigido. Eu pensei que pode ser útil no futuro, se alguém tem problema semelhante.

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

Aqui está um melhor:

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

}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top