Domanda

che sto facendo esercizio ++ un'altra C. Devo calcolare il valore di pi greco dalla serie infinita:

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

Il programma deve stampare il valore approssimativo di pi greco dopo ciascuno dei primi 1.000 termini di questa serie. Ecco il mio codice:

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

Si compila senza errori e gli avvisi, ma appare solo la finestra della console vuota dopo l'esecuzione. Se rimuovo linea”if (i% 1000 == 0)”, posso vedere che viene eseguito e stampare ogni valore pi greco, ma non si ferma, il che significa che la seconda istruzione if non funziona neanche. Non sono sicuro che altro fare. Sto assumendo è probabilmente un errore logico semplice.

È stato utile?

Soluzione

Bene, io% 1000 non sarà mai = 0, come il vostro contatore va da i = 1, quindi con incrementi di 2. Quindi, i è sempre dispari, e non sarò mai un multiplo di 1000.

Il motivo per cui non è mai termina è che l'algoritmo non converge esattamente 3,14,157 mila - sarà una maggiore precisione sia sotto o sopra approssimazione. Si vuole dire "Quando entro un determinato delta del 3,14,157 mila", in modo da scrivere

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

o qualcosa di simile, per quanto "chiude" si vuole ottenere prima di interrompere.

Altri suggerimenti

Dal momento che mi metto a 1 e l'incremento da 2, i è sempre un numero dispari, così ho% 1000 non sarà mai 0.

si dispone di più di un problema:

A. i% 1000 == 0 non sarà mai vera, perché si sta iterazione solo numeri dispari.

B. PI == 3,14159: non è possibile confrontare i valori doppi proprio così, perché il modo in cui i numeri in virgola mobile sono rappresentati (potete leggere a questo proposito qui in un'altra domanda). in modo per farlo funzionare è necessario confrontare i valori in un altro modo -. Un modo è quello di sottrarre gli uni dagli altri e verificare che il risultato assoluto è inferiore a 0,0000001

  1. Hai problemi di floating point di precisione. Prova if(abs(pi - 3.14159) < 0.000005).
  2. i%1000 non sarà mai, perché 0 i è sempre dispari.

Non dovrebbe essere:

if (counter%1000==0)
  1. i inizia da 1 e quindi incrementa per 2. Pertanto i è sempre dispari e non sarò mai un multiplo di 1000, che è per questo che se (i% 1000 == 0) non passa mai.

  2. Direttamente confrontando i galleggianti non funziona, a causa di problemi di precisione galleggianti. Sarà necessario confrontare che la differenza tra i valori è abbastanza vicino.

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

Generalizzando

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

Il che ci dà un approccio più pulito per ogni termine; i 'esimo termine è dato da:

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

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

Quindi, il nostro ciclo può essere abbastanza semplice, dato qualche numero di iterazioni 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;
}

La tua domanda originale dichiarato "Il programma deve stampare il valore approssimativo di pi greco dopo ciascuno dei primi 1.000 termini di questa serie". Ciò non implica alcuna necessità di verificare se 3.14159 è stato raggiunto, quindi non hanno incluso questa qui. La chiamata pow(-1,i%2) è solo per evitare dichiarazioni if (che sono lenti) e prevenire eventuali complicazioni con il grande i .

Si tenga presente che dopo un certo numero di iterazioni, la differenza tra la grandezza di pi greco e l'ampiezza del termine di correzione (diciamo -4/25) sarà così piccolo che andrà oltre la precisione di un double, in modo da avrebbe bisogno di tipi di maggiore precisione a che fare con esso.

Per impostazione predefinita abs utilizza la macro addominali che è per int. Per i doppi, utilizzare la libreria 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;
}

Ecco il codice corretto. Ho pensato che potrebbe essere utile in futuro, se qualcuno ha problema simile.

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

Qui è uno migliore:

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

}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top