(* The two units used should come after this message. Uncomment several write- commands to get a "fully" operational program rather than this benchmark version. You then also can skip the Timer unit and the two commands from that unit (TimerOn and TimerOff) to make the program much smaller (no float math linked into the program). *) program PiCalc; { The fastest PI calculator you'll ever find... :) } { From bits and pieces picked up mainly from the FidoNet PASCAL echo } { Collected, optimized, unitized, etc. by Bjorn Felten @ 2:203:208 } { Public Domain -- Nov 1994 } { Units needed are at the end !! } uses HugeUtil, Timer; { use Crt if you want fast printout on screen } { don't if you want to be able to redirekt o/p } var words, number : longint; nin, link, pii, a239 : HugePtr; procedure ArcCoTan(n : integer; var angle : Huge); var n2, del, remain : integer; positive : boolean; begin { corresp. integer operations } ZeroHuge(angle,words); { angle := 0 } ZeroHuge(nin^,words); { nin := 0 } ZeroHuge(link^,words); { link := 0 } angle.dat[angle.len] := 1; { angle := 1 } DivHuge(angle,n,angle,remain); { angle := angle div n } n2 := n*n; { n2 := n * n } del := 1; { del := 1 } positive := true; CopyHuge(angle,nin^); { nin := angle } repeat DivHuge(nin^,n2,nin^,remain); { nin := nin div n2 } inc(del, 2); { del := del + 2 } positive := not positive; DivHuge(nin^,del,link^,remain); { link := nin div del } if positive then AddHuge(angle,link^) { angle := angle + link } else SubHuge(angle,link^); { angle := angle - link } { write(#13,word(del)) } { uncomment to see that program is not dead } until (link^.len <= 1) and (link^.dat[1] = 0); { writeln} { ... and this too } end; { ArcCoTan } begin { writeln('Program to get Pi (',pi:1:17,'...) with large precision.'); } write('Digits(max 40.000): '); readln(number); words := round(number / 4.7) + 3; { appr. 4.7 digits in one word } write(number:6,#9); TimerOn; GetHuge(pii, words+2); GetHuge(a239, words+2); GetHuge(link, words+2); GetHuge(nin, words+2); ArcCoTan(5, pii^); { ATan(1/5) } AddHuge(pii^, pii^); AddHuge(pii^, pii^); { * 4 } ArcCoTan(239, a239^); { ATan(1/239)} SubHuge(pii^, a239^); AddHuge(pii^, pii^); AddHuge(pii^, pii^); { * 4 } TimerOff; { WriteHuge(pii^, number)} { uncomment if you want printout } end. unit HugeUtil; interface const HugeMax = $8000-16; type Huge = record len : word; dat : array[1..HugeMax] of word; end; HugePtr = ^Huge; procedure AddHuge (var Answer, Add : Huge); procedure MulHuge (var A : Huge; Mul : integer; var Answer : Huge); procedure DivHuge (var A : Huge; Del : integer; var Answer : Huge; var Remainder : integer); procedure SubHuge (var Answer, Sub : Huge); procedure ZeroHuge (var L : Huge; Size : word); procedure CopyHuge (var Fra,Til : Huge); procedure GetHuge (var P : HugePtr; Size : word); procedure WriteHuge(var L : Huge; Size: word); implementation procedure AddHuge; assembler; asm cld push ds lds di,Answer les si,Add seges lodsw mov cx,ax clc @l1: seges lodsw adc [si-2],ax loop @l1 jnb @done @l2: add word [si],1 inc si inc si jc @l2 @done: mov si,di lodsw shl ax,1 add si,ax lodsw or ax,ax je @d2 inc word [di] @d2: pop ds end; procedure MulHuge; assembler; asm cld push ds lds si,A mov bx,Mul les di,Answer mov cx,[si] mov dx,si inc di inc di clc @l1: mov ax,[di] pushf mul bx popf adc ax,si stosw mov si,dx loop @l1 adc si,0 mov es:[di],si lds di,A mov di,[di] mov ax,[di+2] or ax,ax je @l2 inc di inc di @l2: lds si,Answer mov [si],di pop ds end; procedure DivHuge; assembler; asm std push ds lds si,A mov bx,Del les di,Answer mov cx,[si] mov di,cx add di,cx xor dx,dx @l1: mov ax,[di] div bx stosw loop @l1 lds si,Remainder mov [si],dx lds si,A mov ax,[si] lds di,Answer mov [di],ax mov si,[di] shl si,1 @d3: lodsw or ax,ax jne @d2 dec word [di] jne @d3 inc word [di] @d2: pop ds end; procedure SubHuge; assembler; asm cld push ds lds di,Answer les si,Sub seges lodsw mov cx,ax clc @l1: seges lodsw sbb [si-2],ax loop @l1 jnb @done @l2: sub word [si],1 inc si inc si jc @l2 @done: mov si,[di] shl si,1 std @d3: lodsw or ax,ax jne @d2 dec word [di] jne @d3 inc word [di] @d2: pop ds end; procedure WriteHuge; var L1, L2, I, R, R1, X : integer; begin with L do begin L1 := Len; L2 := L1 - 1; I := 1; write(dat[L1],'.'); X := 0; for I := 1 to Size div 4 do begin Dat[L1] := 0; Len := L2; MulHuge(L,10000,L); R := dat[L1]; R1 := R div 100; R := R mod 100; write(chr(R1 div 10+48), chr(R1 mod 10+48), chr(R div 10+48), chr(R mod 10+48)); inc(X); write(' '); if X > 14 then begin writeln; write(' '); X := 0 end end end; writeln end; { WriteHuge } procedure ZeroHuge; begin fillchar(L.Dat, Size * 2, #0); L.Len := Size end; procedure CopyHuge; begin move(Fra, Til, Fra.Len * 2 + 2) end; procedure GetHuge; var D : ^byte; Tries, Bytes : word; begin Bytes := 2 * (Size + 1); Tries:=0; repeat getmem(P,Bytes); { To make it possible to use maximally large arrays, and to increase the speed of the computations, all records of type Huge MUST start at a segment boundary! } if ofs(P^) = 0 then begin ZeroHuge(P^,Size); exit end; inc(Tries); freemem(P,Bytes); new(D) until Tries>10; { if not done yet, it's not likely we ever will be } writeln('Couldn''t get memory for array'); halt(1) end; { GetHuge } end. unit Timer; interface procedure TimerOn; procedure TimerOff; implementation var Time : Longint absolute $0040:$006C; WaitTime, Temp : Longint; procedure TimerOn; begin WaitTime:=Time end; procedure TimerOff; begin Temp:=Time; writeln('Done! It took ',(Temp-WaitTime)/18.2:6:2,'s.') end; end.