Question

Je fais l'exercice d'un autre C. Je dois calculer la valeur de pi de la série infinie:

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

Le programme doit imprimer la valeur approximative de pi après chacun des 1000 premiers termes de cette série. Voici mon code:

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

Il compile sans erreurs et avertissements, mais la fenêtre de la console vide apparaît après l'exécution. Si je supprime la ligne » if (i == 0% 1000) », je peux le voir ne fonctionne et imprimer toutes les valeurs pi, mais il ne s'arrête pas, ce qui signifie que la seconde instruction if ne fonctionne pas non plus. Je ne sais pas quoi faire d'autre. Je suppose qu'il est probablement une simple erreur logique.

Était-ce utile?

La solution

Eh bien, i% 1000 ne sera jamais = 0, comme compteur va de i = 1, puis par incréments de 2. Par conséquent, i est toujours étrange, et ne sera jamais un multiple de 1000.

La raison pour laquelle il se termine jamais est que l'algorithme ne converge pas exactement 3,14157 - ce sera une plus grande précision soit sur ou sous approximation. Vous voulez dire « Lorsque dans un delta donné de 3,14157 », donc écrire

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

ou quelque chose de semblable, pour toutefois « fermer » vous voulez obtenir avant de vous arrêter.

Autres conseils

Puisque vous commencez i à 1 et l'incrément de 2, i est toujours un nombre impair, donc je% 1000 ne sera jamais 0.

vous avez plus d'un problème:

A. i% 1000 == 0 ne sera jamais vrai parce que nous parcourons que des nombres impairs.

B. pi == 3,14159: vous ne pouvez pas comparer les valeurs doubles juste comme ça parce que la façon dont les nombres à virgule flottante sont représentés (vous pouvez lire à ce sujet ici dans une autre question). pour qu'il fonctionne, vous devez comparer les valeurs d'une autre manière -. Une façon est de les soustraire de l'autre et vérifier que le résultat absolu est inférieur à 0,0000001

  1. Vous avez des problèmes de précision flottante point. Essayez if(abs(pi - 3.14159) < 0.000005).
  2. i%1000 ne sera jamais 0 car i est toujours bizarre.

devrait-il pas:

if (counter%1000==0)
  1. i commence à 1 et incrémente par 2. Par conséquent, i est toujours étrange et ne sera jamais un multiple de 1000, ce qui explique pourquoi si (i% 1000 == 0) ne passe jamais.

  2. Comparer directement les flotteurs ne fonctionne pas, en raison de problèmes flottants de précision. Vous aurez besoin de comparer que la différence entre les valeurs est assez proche.

pi = 4 - + 4/3 04/05 au 04/07 + 4/9 -4/11 + ...

Généraliser

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

Ce qui nous donne une approche propre à chaque terme; i 'e terme est donné par:

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

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

Ainsi, notre boucle peut être assez simple, étant donné un certain nombre d'itérations 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;
}

Votre question initiale a déclaré: « Le programme doit imprimer la valeur approximative de pi après chacun des 1000 premiers termes de cette série ». Cela ne signifie pas qu'il soit nécessaire de vérifier si 3,14159 a été atteint, alors je n'ai pas compris cela ici. L'appel pow(-1,i%2) est juste pour éviter les déclarations de if (qui sont lentes) et de prévenir toute complication avec grand i .

Sachez que, après un certain nombre d'itérations, la différence entre l'ampleur de pi et l'ampleur du terme de correction (par exemple -4/25) sera si petit qu'il ira au-delà de la précision d'un double, de sorte que vous aurait besoin des types de précision plus élevés pour y faire face.

Par abs par défaut utilise la macro abs qui est pour int. En double, utilisez la bibliothèque 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;
}

Voici le code corrigé. Je pensais que ce peut être utile à l'avenir si quelqu'un a un problème similaire.

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

Voici une meilleure:

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

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top