(* This program computes PI by the formula: pi / 4 = 4 * ArcTan(1/5) - ArcTan(1/239) Adapted from some program I found on the internet a long time ago that computed PI by: pi / 4 = ArcTan(1/2) + ArcTan(1/3) I have no idea who wrote the original program nor remember where I found it--there wasn't any credits in the original C source. This one also no longer looks like the original as I've completely rewritten it. I got a lot of my information from http://www.boo.net/~jasonp/pipage.html when I rewrote the program. This program will reliably compute upto 1,000,000 digits, that I've verified. There are faster ways of computing PI, and this program probably could be optimized further, but it is sufficiently fast for computing PI using relativly portable and understandable routines that can be easily converted into other languages. Computing PI using FFTs are much much faster, but also much much more complicated. Using the ArcTan methods are fairly simple to implement, but not nearly as fast as the FFT methods. Also, the pi / 4 = 4 * ArcTan(1/5) - ArcTan(1/239) formula is one of the faster of the various ArcTan formulas for computing PI. Author: M. Scott Reynolds Date: 09 September 2006 *) program Pi; uses SysUtils; const // Change PRECISION to compute more digits of pi. PRECISION = 33334; TOTAL_DIGITS = PRECISION * 3; SIZE = 1000; var remainder1, remainder2, remainder3, remainder4: LongInt; b, n, n2, carry: LongInt; i, l: Integer; isZero: Boolean; p: array [0..PRECISION] of LongInt; t: array [0..PRECISION] of LongInt; start, finish: Comp; text: array [0..TOTAL_DIGITS] of Char; begin // Initialize t. for i := 0 to PRECISION do begin t[i] := 0; end; // Note, borrows and carries from the addition and subtraction // are postponed till last. See: http://www.boo.net/~jasonp/ord start := TimeStampToMSecs(DateTimeToTimeStamp(Now)); // Compute arctan(1/5) // t = t / 5, p = t t[0] := 1; remainder1 := 0; for i := 0 to PRECISION do begin b := SIZE * remainder1 + t[i]; t[i] := b div 5; p[i] := t[i]; remainder1 := b mod 5; end; // While t is not zero. n := -1; n2 := 1; repeat // t = t / 25, p = p - t / n, t = t / 25, p = p + t / (n+2) remainder1 := 0; remainder2 := 0; remainder3 := 0; remainder4 := 0; isZero := True; Inc(n, 4); Inc(n2, 4); for i := 0 to PRECISION do begin b := SIZE * remainder1 + t[i]; t[i] := b div 25; remainder1 := b mod 25; b := SIZE * remainder2 + t[i]; p[i] := p[i] - b div n; remainder2 := b mod n; b := SIZE * remainder3 + t[i]; t[i] := b div 25; remainder3 := b mod 25; b := SIZE * remainder4 + t[i]; p[i] := p[i] + b div n2; remainder4 := b mod n2; if isZero and (t[i] <> 0) then // is t zero? isZero := false; end; until isZero; // p = p * 4 carry := 0; for i := PRECISION downto 0 do begin b := p[i] * 4 + carry; p[i] := b mod SIZE; carry := b div SIZE; end; // Compute arctan(1/239) // t = t / 239, p = p - t t[0] := 1; remainder1 := 0; for i := 0 to PRECISION do begin b := SIZE * remainder1 + t[i]; t[i] := b div 239; p[i] := p[i] - t[i]; remainder1 := b mod 239; end; // While t is not zero. n := -1; n2 := 1; repeat // t = t / 57121, p = p + t / n, t = t / 57121, p = p - t / (n+2) remainder1 := 0; remainder2 := 0; remainder3 := 0; remainder4 := 0; isZero := True; Inc(n, 4); Inc(n2, 4); for i := 0 to PRECISION do begin b := SIZE * remainder1 + t[i]; t[i] := b div 57121; remainder1 := b mod 57121; b := SIZE * remainder2 + t[i]; p[i] := p[i] + b div n; remainder2 := b mod n; b := SIZE * remainder3 + t[i]; t[i] := b div 57121; remainder3 := b mod 57121; b := SIZE * remainder4 + t[i]; p[i] := p[i] - b div n2; remainder4 := b mod n2; if isZero and (t[i] <> 0) then // is t zero? isZero := false; end; until isZero; // p = p * 4 carry := 0; for i := PRECISION downto 0 do begin b := p[i] * 4 + carry; p[i] := b mod SIZE; carry := b div SIZE; end; // Borrow and carry. for i := PRECISION downto 1 do begin if p[i] < 0 then begin b := p[i] div SIZE; p[i] := p[i] - (b - 1) * SIZE; p[i-1] := p[i-1] + b - 1; end; if p[i] >= SIZE then begin b := p[i] div SIZE; p[i] := p[i] - b * SIZE; p[i-1] := p[i-1] + b; end; end; finish := TimeStampToMSecs(DateTimeToTimeStamp(Now)); // Store results in string buffer. StrFmt(@text[0], '%d', [p[0]]); l := 1; for i := 1 to PRECISION do begin StrFmt(@text[l], '%.3d', [p[i]]); Inc(l, 3); end; // Print formated results. WriteLn('pi = ', text[0], '.'); for i := 1 to TOTAL_DIGITS do begin Write(text[i]); if (i mod 1000) = 0 then begin WriteLn; WriteLn; end else if (i mod 50) = 0 then WriteLn else if (i mod 10) = 0 then Write(' '); end; WriteLn; WriteLn(finish - start, ' ms to compute ', PRECISION, ' digits of PI.'); end.