(****************************************************************)
(*
** ARIBAS code to calculate pi to many decimal places
** author: Otto Forster <forster@mathematik.uni-muenchen.de>
**
** Example call:
** ==> pi_chud(2000).
*)
(*--------------------------------------------------------------*)
(*
** Algorithmen zur Berechnung von pi und der Eulerzahl e
** auf viele Dezimalen (n <= 20000).
** pi_machin(n) berechnet pi nach der Machinschen Formel
**	auf n Dezimalstellen genau;
** pi_agm(n) benutzt zur Berechnung das arithmetisch-geometrische
**	Mittel.
** pi_chud(n) benutzt eine Methode von Ramanujam-Chudnowski
**
** euler(n) berechnet e auf n Dezimalstellen.
** Der Funktionswert ist jeweils eine ganze Zahl. Diese entspricht
** gerundet 10**n-mal pi bzw. e.
*)
(*--------------------------------------------------------------*)
(*
** Berechnet zz*log(2)
*)
function log2(zz)
var
        x, u, k;
begin
        x := 0;
        k := 0;
        u := (zz * 2**16 * 2) div 3
        while u /= 0 do
                x := x + u div (2*k + 1);
                u := u div 9;
                inc(k);
        end;
        return x div 2**16;
end.
(*------------------------------------------------------*)
(*
** Berechnet zz*arctan(1/n), wird von pi_machin benutzt
*)
function atan1(zz,n)
var
        x, u, v, k, nn;
begin
        x := 0;
        k := 0;
        nn := n*n;
        u := zz div n;
        while u /= 0 do
                v := u div (2*k + 1);
                if even(k) then
                        x := x + v;
                else
                        x := x - v;
                end;
                u := u div nn;
                inc(k);
        end;
        return x;
end.
(*------------------------------------------------------*)
(*
** Berechnet pi * 10**n nach der Machinschen Formel
**
** Beispiel-Aufruf: pi_machin(1000).
*)
function pi_machin(n)
var     z1, x;
begin
        z1 := 10**n * 2**16;
        x := 16 * atan1(z1,5) - 4 * atan1(z1,239);
        return x div 2**16;
end.
(*------------------------------------------------------*)
(*
** Berechnet exp(1) * 10**n
*)
function euler(n)
var     zz, x, k;
begin
        zz := 10**n * 2**16;
        x := zz * 2;
        k := 2;
        while zz /= 0 do
                zz := zz div k;
                x := x + zz;
                inc(k);
        end;
        return x div 2**16;
end.
(*------------------------------------------------------*)
(*
** Berechnet pi * 10**n,
** benutzt arithmetisch-geometrisches Mittel
** quadratische Konvergenz
**
** Beispiel-Aufruf: pi_agm(1000).
*)
function pi_agm(n)
var     zz;
begin
        zz := 10**n * 2**16;
        return piaux(zz) div 2**16;
end.
(*------------------------------------------------------*)
(*
** Hilfsfunktion fuer pi_agm
*)
function piaux(zz)
var     s, a, atemp, b, c, i;
begin
        s := 0;
        a := zz;
        b := isqrt(zz * (zz div 2));
        c := (a - b) div 2;
        i := 1;
        while c /= 0 do
                writeln("eps(",i,") = ",c/zz);
                s := s + (2**i * c * c) div zz;
                atemp := a;
                a := (a + b) div 2;
                b := isqrt(atemp * b);
                c := (a - b) div 2;
                inc(i);
        end;
        return (4*a*a) div (zz - 2*s);
end.
(*------------------------------------------------------*)
(*
** Hilfsfunktion fuer pi_chud
*)
function Saux(zz)
const
	k1 = 545140134;
	k2 = 13591409;
	k4 = 100100025;
	k5 = 327843840;
var
	A, n: integer;
	S: integer;
begin
	A := zz*k1;
	S := A * k2;
	n := 1;
	while A > 0 do
         	A := A * ((6*n-5)*(6*n-3)*(6*n-1));
		A := A div (n*n*n);
		A := A div (k4*k5);
		if even(n) then
			S := S + A * (k2 + n*k1);
		else
			S := S - A * (k2 + n*k1);
		end;
		inc(n);
	end;
	return S div k1;
end;
(*--------------------------------------------------------*)
(*
** pi auf n Dezimalstellen nach Chudnowsky/Ramanujan 
*)
function pi_chud(n: integer): integer;
const
        k3 = 640320;
        k6 = 53360;
var
  	zz: integer;
	x: integer;
begin
	zz := 2**16 * 10**n;
	x := isqrt(zz*zz*k3)*k6;
	x := (zz * x) div Saux(zz);
	return (x div 2**16);
end;
(*--------------------------------------------------------*)

