[C]Calcular pi

Iniciado por HRSLASH, 10 Agosto 2010, 19:47 PM

0 Miembros y 1 Visitante están viendo este tema.

HRSLASH

Hola gente!! dejo unos programitas que hice para calcular pi con distintas series infinitas.. y ya q los posteo aprovecho para dejar unas dudas q tengo..

Algoritmo Gottfried Wilhem von Leibniz
= 4(1/1-1/3+1/5-1/7+1/9...)


#include<stdio.h>

main()
{
      int i, j = 1;
      double pi = 0, rtdo;
     
      for (i = 0; i < 1000000000; i++){
          rtdo = 4 / (double)j;
         
               if (i % 2 == 1)
                  pi -= rtdo;
               else
                   pi += rtdo;
          j += 2;
      }
     
      printf("Valor de Pi: %.16f", pi);
     
      return 0;
}


Algoritmo John Wallis
= 2 ( 2/1 x 2/3 x 4/3 x 4/5 x 6/5 x 6/7 ....)


#include<stdio.h>

main()
{
      int i, j = 2, k = 1;
      double pi = 2;
     
      for (i = 0; i < 1000000000; i++){
          pi *= (j / (double)k);
           
          if (i % 2 == 0)
             k += 2;
          else
              j += 2;
      }
     
      printf("Valor de Pi: %.16f", pi);
     
      return 0;
}


Estos 2 funcionan bien pero me devuelven solo 16 decimales, desp de ese devuelve todo 0.. pq??

Algoritmo Leonhard Euler
=  1 + 1/3 + 1x2 / 3x5 + 1x2x3 / 3x5x7 +....


#include<stdio.h>

main()
{
      int i, cte = 1, cte2 = 1;
      double pi = 1, j = 1, k = 1;
     
      for (i = 0; i < 100; i++){
          j *= cte++;
          k *= (cte2 += 2);
         
          pi += (j / k);
          }
     
      printf("%.15f", pi);
     
      return 0;
}


En este tengo el problema de q como se forman nº tan grandes no puedo hacer un bucle de mas de 100 vueltas y ademas no da el rtdo, no pude encontrarle solucion, creo q el codigo esta bien hecho..

Saludos! :D
La televisión es para mi el medio mas instructivo y cultural que conozco, cuando la prenden me voy a leer

leogtz

#1
En el algoritmo "Algoritmo Gottfried Wilhem von Leibniz" corrigiendo errores, usando variables register y compilando "agresivamente" con gcc se puede calcular en unos 45 segundos a 32 decimales:

#include <stdio.h>

int main(void)
{
     register unsigned long long int i, j = 2, k = 1;
     long double pi = 2.0;

     for (i = 0; i < 1000000000; ++i)
     {
         pi *= (j / (double)k);

         if (!(i & 1))
            k += 2;
         else
             j += 2;
     }
     printf("Pi : %.32llf\n", pi);
     return 0;
}



leo@lein:~/Escritorio/c_proyect/intgrande$ cat code.c
#include <stdio.h>

int main(void)
{
     register unsigned long long int i, j = 2, k = 1;
     long double pi = 2.0;

     for (i = 0; i < 1000000000; ++i)
     {
         pi *= (j / (double)k);

         if (!(i & 1))
            k += 2;
         else
             j += 2;
     }
     printf("Pi : %.32llf\n", pi);
     return 0;
}
leo@lein:~/Escritorio/c_proyect/intgrande$ gcc code.c -O1 -O2 -O3 -o code
leo@lein:~/Escritorio/c_proyect/intgrande$ time ./code
Pi : 3.14159265201900078298691276756927

real    0m46.795s
user    0m44.851s
sys     0m0.072s
leo@lein:~/Escritorio/c_proyect/intgrande$ time ./code
Pi : 3.14159265201900078298691276756927

real    0m46.149s
user    0m44.575s
sys     0m0.052s
leo@lein:~/Escritorio/c_proyect/intgrande$


Y este:

#include <stdio.h>

int main()
{
     unsigned long long int i, cte = 1, cte2 = 1;
     long double pi = 1.0, j = 1.0, k = 1.0;

     for (i = 0; i < 1000; ++i)
     {
         j *= (double)cte++;
         k *= (double)(cte2 += 2);
         pi += (j / k);
         }

     printf("%.15llf", pi);

     return 0;
}

No creo que funcione, incluso con i <1000 no calcula bien:


leo@lein:~/Escritorio/c_proyect/intgrande$ ./code
1.570796326794897
leo@lein:~/Escritorio/c_proyect/intgrande$


Aquí otra manera de construirlo.

/* Construcción del número pi */
#include <stdio.h>
#include <math.h>
int main(void)
{
    signed int i = 1;
    long double suma = 0.0;
    for(; i <= 1000000   ; i++)
    suma += (double)pow(-1.0, i + 1.0) / (2.0 * i - 1.0);
    suma *= 4.0;
    printf("%.32llf\n", suma);
    return 0;
}


leo@lein:~/Escritorio/c_proyect/intgrande$ cat code.c
/* Construcción del número pi */
#include <stdio.h>
#include <math.h>
int main(void)
{
    signed int i = 1;
    long double suma = 0.0;
    for(; i <= 1000000   ; i++)
    suma += (double)pow(-1.0, i + 1.0) / (2.0 * i - 1.0);
    suma *= 4.0;
    printf("%.32llf\n", suma);
    return 0;
}
leo@lein:~/Escritorio/c_proyect/intgrande$ gcc code.c -o code -O1 -O2 -O3 -lm
leo@lein:~/Escritorio/c_proyect/intgrande$ ./code
3.14159165358979318525417534502253
leo@lein:~/Escritorio/c_proyect/intgrande$ time ./code
3.14159165358979318525417534502253

real    0m0.276s
user    0m0.276s
sys     0m0.000s
leo@lein:~/Escritorio/c_proyect/intgrande$
Código (perl) [Seleccionar]

(( 1 / 0 )) &> /dev/null || {
echo -e "stderrrrrrrrrrrrrrrrrrr";
}

http://leonardogtzr.wordpress.com/
leogutierrezramirez@gmail.com

HRSLASH

Hola leo!! gracias por tu ayuda!! ahora tengo un problema.. cuando copio el codigo q escribiste y lo pego en el dev-c++, al compilarlo me muestra cualquier numero, esta copiado identico pero no funciona :-\ es pq no uso el gcc?
otra preg, pq usas el tipo register? y la ultima.. q significa esta condicion(i & 1), estaba mal la q habia puesto antes??
Bueno espero tu rta :D
Saludo!!
La televisión es para mi el medio mas instructivo y cultural que conozco, cuando la prenden me voy a leer

leogtz

Cita de: HRSLASH en 10 Agosto 2010, 23:23 PM
otra preg, pq usas el tipo register? y la ultima.. q significa esta condicion(i & 1), estaba mal la q habia puesto antes??
Bueno espero tu rta :D
Saludo!!

El código funciona bien con gcc que es el que uso, no sé como funcionará con MingW.

El especificador register pone las variables en un registro del CPU en lugar de estar en la memoria, es por esto que las operaciones con las variables register se hacen mucho más rápido.
Código (perl) [Seleccionar]

(( 1 / 0 )) &> /dev/null || {
echo -e "stderrrrrrrrrrrrrrrrrrr";
}

http://leonardogtzr.wordpress.com/
leogutierrezramirez@gmail.com

Littlehorse

En realidad el especificador register no es mas que una "sugerencia", en todo caso es el compilador el que decide si hacer caso o no a esa "sugerencia".

En otras épocas se utilizaba, pero en la actualidad la complejidad subyacente es otra por tanto el compilador hace un mejor trabajo optimizando código que nosotros, por lo menos en la gran mayoría de los casos.

De hecho, Visual Studio ni siquiera acepta la sugerencia:

CitarThe compiler does not accept user requests for register variables; instead, it makes its own register choices when global register-allocation optimization (/Oe option) is on. However, all other semantics associated with the register keyword are honored.

y GCC lo ignora en caso que la dirección de la variable se solicite en cualquier punto del programa.

Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

leogtz

Claro, Littlehorse, pero qué mejor que decidirlo por nosotros mismos y no el compilador, es decir, ser lo más explícito posible.

En el ejemplo que puse solo se usa para control de bucles, así que no creo que haya problemas en eso.
Código (perl) [Seleccionar]

(( 1 / 0 )) &> /dev/null || {
echo -e "stderrrrrrrrrrrrrrrrrrr";
}

http://leonardogtzr.wordpress.com/
leogutierrezramirez@gmail.com

Littlehorse

Claro pero, repito, no es una decisión, es una sugerencia que el compilador es libre de ignorar por completo, y de hecho lo hacen en mas de una oportunidad.

Lo aclaro para que no quede la falsa idea que utilizar variables locales register si o si mejora el rendimiento de un programa, ya que esto solo ocurriría en ciertas oportunidades y solamente cuando el compilador lo decida. En el peor de los casos, demasiadas variables register podrían empeorar el rendimiento del programa final.

Saludos

An expert is a man who has made all the mistakes which can be made, in a very narrow field.

misterharry


Cita de: HRSLASH en 10 Agosto 2010, 23:23 PM
q significa esta condicion(i & 1), estaba mal la q habia puesto antes??

en realidad no estaba mal...

& tambien es un operador binario (operador AND) y en este caso esta comparando el valor binario de "i" con 1
ej:
       si i=3 en binario seria 00000011, entonces 00000011 & 1 = 1
       si i=2 en binario seria 00000010, entonces 00000010 & 1 = 0

esta siendo utilizado para verificar si el numero es impar :)

es decir ( i & 1) es equivalente a (i % 2 == 1)