Seguramente todos los lectores han oído mencionar este número denominado con la letra griega π (Pi). Frecuentemente utilizado por los matemáticos, físicos, arquitectos e ingenieros, nos ha devuelto tanto soluciones como fuertes dolores de cabeza. A continuación publicamos un algoritmo que permite calcular el valor exacto de Pi hasta 10 000 cifras decimales; lo demás sólo depende del nivel de procesamiento de la computadora donde se ejecute el programa.
#include <iostream>
#include <fstream>
#include <cstdio>
using namespace std;
/*
Calculando un gran número:
Elaborado por Harvin Manuel Toledo
Basado en la página de: Xavier Gourdon
harvin_t@hotmail.com, harvin_t@yahoo.es
Empleé dos formulas para comprobar que el programa no se equivoca:
pi=4*(4*arctan(1/5)-arctan(1/239))
pi=4*(arctan(1/2)+arctan(1/3))
y usando la fórmula arctan(x)=x-x^3/3+x^5/5-x^7/7+x^9/9. Esta es llamada también
la serie de Leibniz.
Para hacer un cálculo más rápido podemos usar las identidades
siguientes para comprobar nuestro cálculos
Estas fórmulas fueron usadas por Yasumasa Kanada en el récord que rompió en 2002
en Tokio, Japón con más de un billón de cifras de Pi
pi=48*arctan(1/49)+128*arctan(1/57)-20*arctan(1/239)+48*arctan(1/110443)
pi=176*arctan(1/57)+28*arctan(1/239)-48*arctan(1/682)+96*arctan(1/12943)
*/
//definir la base en la que se harán las operaciones
const long B=10000;
const long LB=4;
const long Digitos=10000; //si alteras este número obtendrás más digitos
//Declaraciones
void Imprimir(long, long *);
void Archivar(long, long *);
void Mult(long, long *, long);
void Div(long, long *, long);
void Sum(long , long *, long *);
void Rest(long , long *, long *);
void HacerEntero(long, long *, long);
bool EsCero(long, long *);
int main()
{
bool signo;
long *arctan1, *arctan2, *pi, *term;
long k;
long tam;
tam=Digitos/LB+1;
arctan1=new long[tam];
arctan2=new long[tam];
pi=new long[tam];
term=new long[tam];
cout<<"Memoria reservada con éxito"<<endl;
cout<<"El programa ha comenzado a calcular, espere un momento..."<<endl;
HacerEntero(tam, arctan1, 0);
HacerEntero(tam, arctan2, 0);
HacerEntero(tam, pi, 0);
k=1;
signo=false;
HacerEntero(tam, term, 1);
Div(tam, term, 5);
Sum(tam, arctan1, term);
while(!EsCero(tam, term))
{
Div(tam, term, 25);
Div(tam, term, 2*k+1);
if(signo)
Sum(tam, arctan1, term);
else
Rest(tam, arctan1, term);
if(signo)
signo=false;
else
signo=true;
Mult(tam, term, 2*k+1);
k++;
}
Mult(tam, arctan1, 4);
k=1;
signo=false;
HacerEntero(tam, term, 1);
Div(tam, term, 239);
Sum(tam, arctan2, term);
while(!EsCero(tam, term))
{
Div(tam, term, 57121);
Div(tam, term, 2*k+1);
if(signo)
Sum(tam, arctan2, term);
else
Rest(tam, arctan2, term);
if(signo)
signo=false;
else
signo=true;
Mult(tam, term, 2*k+1);
k++;
}
Sum(tam, pi, arctan1);
Rest(tam, pi, arctan2);
Mult(tam, pi, 4);
Imprimir(tam, pi);
Archivar(tam, pi);
cin.ignore();
delete[] arctan1;
delete[] arctan2;
delete[] term;
delete[] pi;
}
void Imprimir(long n, long *x)
{
long i=0;
printf("%d.", x[0]);
for(i=1; i<n-1; i++)
printf("%.4d", x[i]);
}
void Archivar(long n, long *x)
{
FILE *pArchivo;
pArchivo=fopen("pi.txt", "w");
long i=0;
fprintf(pArchivo, "Elaborado por harvin toledo\n");
fprintf(pArchivo, "El valor pi es: ");
fprintf(pArchivo, "%d.", x[0]);
for(i=1; i<n-1; i++)
fprintf(pArchivo, "%.4d", x[i]);
fclose(pArchivo);
}
/* Esta función multiplica un gran número por un entero común
no mayor que sizeof(long),
el resultado es almacenado en el mismo x
*/
void Mult(long n, long *x, long q)
{
long i=0;
long lleva=0, xi;
for(i=n-1; i>=0; i--)
{
xi=x[i]*q+lleva;
if(xi>B)
{
lleva=xi/B;
xi-=lleva*B;
}
else
lleva=0;
x[i]=xi;
}
x[0]+=lleva*B;
}
/* Esta funcion divide un gran número por un entero común
no mayor que sizeof(long)
el resultado es almacenado en el mismo x
*/
void Div(long n, long *x, long q)
{
long i, lleva=0, xi;
for(i=0; i<n; i++)
{
xi=x[i]+lleva*B;
x[i]=xi/q;
lleva=xi-x[i]*q;
}
}
/* Esta función suma un gran número en multiprecisión con otro
del mismo tipo y el resultado lo almacena en el primero o sea x
*/
void Sum(long n, long *x, long *y)
{
long i, lleva=0;
for(i=n-1; i>=0; i--)
{
x[i]+=y[i]+lleva;
if(x[i]>=B)
{
x[i]-=B;
lleva=1;
}
else
lleva=0;
}
}
/*Esta función resta dos números en multiprecisión
y almacena el nuevo resultado en el primero*/
void Rest(long n, long *x, long *y)
{
long i, lleva=0;
for(i=n-1; i>=0; i--)
{
x[i]=x[i]-y[i]-lleva;
if(x[i]<0)
{
x[i]+=B;
lleva=1;
}
else
lleva=0;
}
}
/*Esta función convierte un entero menor que sizeof(long),
en un entero con multiprecisión*/
void HacerEntero(long n, long *x, long Entero)
{
long i;
x[0]=Entero;
for(i=1; i<n; i++)
x[i]=0;
}
//Esta función averigua si un número en multiprecisión
//es igual a cero o no
bool EsCero(long n, long *x)
{
long i;
for(i=0; i<n; i++)
{
if(x[i])
return false;
}
return true;
}
