Pregunta

Estoy haciendo ejercicio otra C ++. Tengo que calcular el valor de pi de la serie infinita:

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

El programa tiene que imprimir el valor aproximado de pi después de cada uno de los primeros 1.000 términos de esta serie. Aquí está mi 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;
}

Se compila sin errores y advertencias, pero sólo aparece la ventana de consola vacía después de la ejecución. Si quito la línea”si (i% 1000 == 0)”, puedo ver que se ejecuta e imprimir cada valor de pi, pero no se detiene, lo que significa la segunda sentencia if no funciona bien. No estoy seguro de qué otra cosa hacer. Estoy asumiendo que es probablemente un error de lógica simple.

¿Fue útil?

Solución

Bueno, i% 1000 nunca se = 0, ya que su contador va desde i = 1, entonces en incrementos de 2. Por lo tanto, siempre es impar, y nunca será un múltiplo de 1.000.

La razón por la que nunca termina es que el algoritmo no converge a exactamente 3,14157 - que va a ser una precisión superior, ya sea bajo o sobre la aproximación. Que quiere decir "Cuando dentro de un delta dada de 3,14157", así que escriba

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

o algo similar, sin embargo para "cerrar" desea obtener antes de dejar.

Otros consejos

Desde que inicie i en 1 y el incremento en un 2, que siempre es un número impar, por lo que 1000% nunca será 0.

tiene más de un problema:

A. i == 0% 1000 nunca ser verdad porque estás iterando sólo números impares.

B. == pi 3,14159: no se puede comparar los valores dobles al igual que debido a la forma en que los números de coma flotante se representan (se puede leer sobre ello aquí en otra pregunta). con el fin de que funcione debe comparar los valores de otra manera -. Una forma es restar unos de otros y comprobar que el resultado absoluto es menor que 0,0000001

  1. Usted ha flotante de precisión cuestiones puntuales. Trate if(abs(pi - 3.14159) < 0.000005).
  2. i%1000 nunca será 0 porque i es siempre impar.

¿No debería ser:

if (counter%1000==0)
  1. i comienza en 1 y luego incrementos por 2. Por lo tanto i siempre es impar y nunca será un múltiplo de 1000, que es por eso que si (i% 1000 == 0) no pasa.

  2. comparar directamente los flotadores no funciona, debido a problemas de precisión flotantes. Usted tendrá que comparar la diferencia entre los valores es lo suficientemente cerca.

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

Generalizando

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

Lo que nos da un enfoque más limpio para cada término; la i 'th plazo está dada por:

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

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

Por lo tanto, nuestro bucle puede ser bastante simple, dado un número de iteraciones 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;
}

Su pregunta original se indica "El programa tiene que imprimir el valor aproximado de pi después de cada uno de los primeros 1.000 términos de esta serie". Esto no implica ninguna necesidad de comprobar si se ha alcanzado 3,14159, así que no he incluido esta aquí. La llamada pow(-1,i%2) es sólo para evitar declaraciones if (que son lentos) y evitar cualquier complicación con gran i .

Tenga en cuenta que después de un número de iteraciones, la diferencia entre la magnitud de pi y la magnitud del término de corrección (por ejemplo -4/25) será tan pequeña que no irá más allá de la precisión de un double, por lo que necesitaría tipos de mayor precisión para tratar con él.

Por abs predeterminado utiliza la macro abs que es para int. En dobles, utilizar la 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;
}

Este es el código corregido. Pensé que podría ser útil en el futuro si alguien tiene un problema similar.

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

Aquí está uno mejor:

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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top