home *** CD-ROM | disk | FTP | other *** search
- (*
- 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.