{--------------------------------------}
function MultiSI.Comp( var X : MultiSI) : Integer; {Comp = sign( Self - X)}
{Sign = -1 if Self < X; Sign = 0 if Self = X; Sign = +1 if Self > X}
{Self.S and X.S used but not changed; Self, X not changed}
begin
if Not S and Not X.S then Comp:= AbComp(X) {Both positive}
else if S and X.S then Comp:= X.AbComp( Self) {Both negative}
else if X.S then Comp:= +1 {Self pos, X neg}
else Comp:= -1; {Self neg, X pos}
end; {MultiSI.Comp}
{--------------------------------------}
procedure WriteMax( var Out : TEXT; St : String);
{Output String and line feed every MuMaxW, MuTot = characters on line so far}
var
I : Integer;
begin
if (@Out = @OutPut) or (MuMaxW <= 0) then Write( Out, St)
else
for I:= 1 to Length( St) do begin
Write( Out, St[I]); Inc( MuTot);
if (MuTot >= MuMaxW) then begin
WriteLn( Out); MuTot:= 0;
end;
end;
end; {WriteMax}
{--------------------------------------}
procedure WriteMaxLn( var Out : TEXT; St : String);
{Output String and line feed every MuMaxW, MuTot = characters on line so far
and a new line}
begin
WriteMax( Out, St);
WriteLn( Out); MuTot:= 0;
end; {WriteMaxLn}
{--------------------------------------}
procedure MultiSI.Writ( var Out : TEXT); {Output Self as a line of text}
{Self is not modified}
var
I, J, ToGo, LenD : LongInt;
St : String[8];
begin
ToGo:= LongInt(N) * MuDMax;
if S then WriteMax( Out, '-');
Str( Base + V^[N - 1] :0:0, St);
J:= 1;
repeat
Inc(J);
until (St[J] <> '0') or (J = MuDMax+1);
WriteMax( Out, St[J]);
Dec( ToGo, J - 1);
LenD:= ToGo + 1;
while J <= MuDMax do begin
Inc(J);
if (ToGo Mod MuDpG) = 0 then WriteMax( Out, ',');
WriteMax( Out, St[J]);
Dec( ToGo);
end;
for I:= 2 to N do begin
Str( Base + V^[N - I] :0:0, St);
for J:= 2 to MuDMax+1 do begin
if (ToGo Mod MuDpG) = 0 then WriteMax( Out, ',');
WriteMax( Out, St[J]);
Dec( ToGo);
end;
end;
if LenD >= MuLenD then begin
Str( LenD, St);
if (@Out <> @OutPut) and (MuMaxW > 0) and
(Length(St) > (MuMaxW - MuTot - 3)) then begin
WriteLn( Out); MuTot:= 0;
end;
if (@Out = @OutPut) or (MuMaxW <= 0) or (MuTot <> 0) then
WriteMax( Out, ' ');
WriteMax( Out, '(' + St + ')');
end;
end; {MultiSI.Writ}
{--------------------------------------}
procedure MultiSI.WritLn( var Out : TEXT); {Output Self and a new line}
begin
Writ( Out);
WriteLn( Out); MuTot:= 0;
end; {MultiSI.WritLn}
{--------------------------------------}
procedure MultiSI.ShortWr( var Out : TEXT; Short : LongInt);
{Output Self in short form ... if more than Short digits}
{Self is not modified}
var
Did : Integer;
I, J, ToGo, LenD : LongInt;
St : String[8];
begin
if (N < 3) or (N <= Short div MuDMax) then begin
Writ( Out); Exit;
end;
ToGo:= LongInt(N) * MuDMax;
if S then Write( Out, '-');
Str( Base + V^[N - 1] :0:0, St);
J:= 1;
repeat
Inc(J);
until (St[J] <> '0') or (J = MuDMax+1);
Write( Out, St[J]); Did:= 1;
Dec( ToGo, J - 1);
LenD:= ToGo + 1;
while (J <= MuDMax) and (Did < 5) do begin
Inc(J);
Write( Out, St[J]); Inc( Did);
end;
Str( Base + V^[N - 2] :0:0, St);
for J:= 2 to 6-Did do begin
Write( Out, St[J]);
end;
Write( Out, ',...,');
Str( Base + V^[0] :0:0, St);
for J:= MuDMax-3 to MuDMax+1 do begin
Write( Out, St[J]);
end;
Write( Out, ' (', LenD, ')');
end; {MultiSI.ShortWr}
{--------------------------------------}
procedure MultiSI.ShortWrLn( var Out: TEXT; Short : LongInt);
{Output Self short and a new line}
begin
ShortWr( Out, Short);
WriteLn( Out); MuTot:= 0;
end; {MultiSI.ShortWrLn}
{--------------------------------------}
procedure MultiSI.RMul1( D1 : Mu1Digit); {Self = Self * D1}
{Multi-precision one super digit multiply; D1 is not changed}
{MuErr set true if Self overflows}
var
K : Mu1Digit;
begin
S:= S xor (D1 < 0);
IpMul1(D1, Self, K);
if K > 0 then
MuWriteErr('One digit multiply overflow, continuing...');
end; {MultiSI.RMul1}
{--------------------------------------}
procedure MultiSI.Mul1( var X : MultiSI; D1 : Mu1Digit); {Self = X * D1}
{Multi-precision one super digit multiply; X and D1 are not changed}
{MuErr set true if Self overflows}
begin
SetTo(X);
RMul1( D1);
end; {MultiSI.Mul1}
{--------------------------------------}
procedure MultiSI.Mul( var X, Y : MultiSI); {Self = X * Y}
{X or Y or both may have the same address in memory as Self}
{X, Y are not changed unless they share memory with Self}
{Sets MuErr True if overflow}
var
XL, YL : ^MultiSI;
I, J, IJ : Integer;
K : Mu1Digit;
T : Mu2Digit;
NewXL, NewYL : Boolean;
begin
XL:= @X; NewXL:= False;
YL:= @Y; NewYL:= False;
if X.V = Self.V then begin
New( XL, Init( X.N)); XL^.SetTo(X); NewXL:= True;
end
else if Y.V = Self.V then begin
New( YL, Init( Y.N)); YL^.SetTo(Y); NewYL:= True;
end;
if @X = @Y then YL:= XL;
S:= XL^.S xor YL^.S;
for I:= 0 to XL^.N-1 do V^[I]:= 0; {Clear lower of Self}
KeyHit:= False;
for J:= 0 to YL^.N-1 do begin
K:= 0; I:= 0;
while I < XL^.N do begin
IJ:= I + J;
if IJ < Self.M then begin {Mult, add and carry next Digit}
T:= XL^.V^[I] * YL^.V^[J] + Self.V^[ IJ] + K;
K:= Int(T / Base);
Self.V^[ IJ]:= T - K * Base;
end
else
I:= XL^.N; {Break out of inner loop}
Inc(I);
end;
Inc( IJ);
if IJ < Self.M then Self.V^[ IJ]:= K;
MuInterrupt;
if MuAbort then begin
Clear;
if NewXL then Dispose( XL, Done);
if NewYL then Dispose( YL, Done);
Exit;
end;
if KeyHit then begin
for I:= 0 to Echo do
WriteLn( OutP[I]^, 'Integer Multiply: ',
Trunc( (100.0 * (J+1)) / YL^.N), ' Percent done');
KeyHit:= False;
end;
end;
if K <> 0 then Inc( IJ);
if IJ > Self.M then begin
IJ:= Self.M;
MuWriteErr('Multiplication overflow, continuing...');
end;
N:= IJ;
Norm;
if NewXL then Dispose( XL, Done);
if NewYL then Dispose( YL, Done);
end; {MultiSI.Mul}
{--------------------------------------}
procedure MultiSI.RMul( var X : MultiSI); {Self = Self * X}
{X may have the same address in memory as Self}
{X is not changed unless it shares memory with Self}
{Sets MuErr True if overflow}
begin
Mul( Self, X);
end; {MultiSI.RMul}
{--------------------------------------}
procedure MultiSI.Sq( var X : MultiSI); {Self = X * X}
{X may have the same address in memory as Self}
{X is not changed unless it shares memory with Self}
{Sets MuErr True if overflow}
begin
Mul(X, X);
end; {MultiSI.Sq}
{--------------------------------------}
procedure MultiSI.RSq; {Self = Self * Self}
{Sets MuErr True if overflow}
begin
Mul( Self, Self);
end; {MultiSI.RSq}
{--------------------------------------}
procedure MultiSI.ModMB; {Self = Self Mod MuMB}
{Self is changed}
var I : Integer; QL : ^MultiSI;
begin
if MuMB^.ZTest then Exit;
I:= AbComp( MuMB^);
if I >= 0 then begin {if |Self| >= |MuMB|}
New( QL, Init( Self.N));
IpDiv( MuMB^, Self, QL^, Self);
Dispose( QL, Done);
end;
end; {MultiSI.ModMB}
{--------------------------------------}
procedure MultiSI.RDiv1( D1 : Mu1Digit); {Self = Self / D1}
{Multi-precision one super digit divide, D1 is not changed}
{Allows literal D1, MuErr set True if D1 = 0}
var
RL : Mu1Digit;
begin
IpDiv1( D1, Self, RL);
end; {MultiSI.RDiv1}
{--------------------------------------}
procedure MultiSI.Div1( var U : MultiSI; D1 : Mu1Digit); {Self = U / D1}
{Multi-precision one super digit divide, D1 and U not changed}
{U and Self may have same address in memory, then U is changed}
{Allows literal D1, MuErr set True if D1 = 0}
var
RL : Mu1Digit;
begin
SetTo(U);
IpDiv1( D1, Self, RL);
end; {MultiSI.Div1}
{--------------------------------------}
procedure MultiSI.Mod1( D1: Mu1Digit; var R1: Mu1Digit); {R1 = Rem( Self / D1)}
{Multi-precision one super digit Modulo, D1 and Self not changed}
{D1 and R1 may have same address in memory, then D1 is changed}
{Allows literal D1, MuErr set True if D1 = 0}
var
QL : ^MultiSI;
begin
New( QL, Init( Self.N));
QL^.SetTo( Self);
IpDiv1( D1, QL^, R1);
Dispose( QL, Done);
end; {MultiSI.Mod1}
{--------------------------------------}
procedure MultiSI.RDiv1QR( D1: Mu1Digit; var R1: Mu1Digit);
{Self = Self / D1, R1 = Rem}
{Multi-precision one super digit Divide Q & R. D1 and U not changed}
{D1 and R1 may have same address in memory, then D1 is changed}
{Allows literal D1, MuErr set True if D1 = 0}
begin
IpDiv1( D1, Self, R1);
end; {MultiSI.RDiv1QR}
{--------------------------------------}
procedure MultiSI.Div1QR( var U: MultiSI; D1: Mu1Digit; var R1: Mu1Digit);
{Self = U / D1, R1 = Rem}
{Multi-precision one super digit Divide Q & R. D1 and U not changed}
{D1 and R1 may have same address in memory, then D1 is changed}
{Allows literal D1, MuErr set True if D1 = 0}
begin
SetTo(U);
IpDiv1( D1, Self, R1);
end; {MultiSI.Div1QR}
{--------------------------------------}
procedure MultiSI.Divi( var U, D : MultiSI); {Self = U / D}
{U or D or both may have the same address in memory as Self}
{U, D are not changed unless they share memory with Self}
{Sets MuErr True if D = 0}
var
DL, RL : ^MultiSI;
NewDL : Boolean;
begin
DL:= @D; NewDL:= False;
if D.V = Self.V then begin
New( DL, Init( D.N)); DL^.SetTo(D); NewDL:= True;
end;
New( RL, Init( U.N)); RL^.SetTo(U);
IpDiv( DL^, RL^, Self, RL^);
if NewDL then Dispose( DL, Done);
Dispose( RL, Done);
end; {MultiSI.Divi}
{--------------------------------------}
procedure MultiSI.RDiv( var D : MultiSI); {Self = Self / D}
{D may have the same address in memory as Self}
{D is not changed unless it shares memory with Self}
{Sets MuErr True if D = 0}
begin
Divi( Self, D);
end; {MultiSI.RDiv}
{--------------------------------------}
procedure MultiSI.Modu( var U, D : MultiSI); {Self = Rem(U / D)}
{U or D or both may have the same address in memory as Self}
{U, D are not changed unless they share memory with Self}
{Sets MuErr True if D = 0}
var
DL, QL : ^MultiSI;
NewDL : Boolean;
begin
DL:= @D; NewDL:= False;
if D.V = Self.V then begin
New( DL, Init( D.N)); DL^.SetTo(D); NewDL:= True;
end;
New( QL, Init( U.N));
SetTo(U);
IpDiv( DL^, Self, QL^, Self);
if NewDL then Dispose( DL, Done);
Dispose( QL, Done);
end; {MultiSI.Modu}
{--------------------------------------}
procedure MultiSI.RMod( var D : MultiSI); {Self = Rem( Self / D)}
{D may have the same address in memory as Self}
{D is not changed unless it shares memory with Self}
{Sets MuErr True if D = 0}
begin
Modu( Self, D);
end; {MultiSI.RMod}
{--------------------------------------}
procedure MultiSI.DivQR( var U, D, R : MultiSI); {Self = U / D, R = Rem}
{U or D or both may have the same address in memory as Self or R}
{U, D are not changed unless they share memory with Self or R}
{Self and R may not have the same location in memory. Sets MuErr True if D = 0}
var
DL : ^MultiSI;
NewDL : Boolean;
begin
if Self.V = R.V then begin
MuWriteErr(
'Cannot set same location to both quotient and remainder, continuing...');
Exit;
end;
DL:= @D; NewDL:= False;
if (D.V = Self.V) or (@D = @R) then begin
New( DL, Init( D.N)); DL^.SetTo(D); NewDL:= True;
end;
R.SetTo(U);
IpDiv( DL^, R, Self, R);
if NewDL then Dispose( DL, Done);
end; {MultiSI.DivQR}
{--------------------------------------}
procedure MultiSI.RDivQR( var D, R : MultiSI); {Self = Self / D, R = Rem}
{Self may have the same address in memory as D or R}
{D is not changed unless it shares memory with Self or R}
{Sets MuErr True if D = 0}
begin
DivQR( Self, D, R);
end; {MultiSI.RDivQR}
{--------------------------------------}
procedure MultiSI.PowMB( var B, P : MultiSI); {Self = (B ** P) Mod MuMB}
{B or P or both may have the same address in memory as Self}
{B, P are not changed unless they share memory with Self}
{Sets MuErr True if overflow or error}
var
BL, PL : ^MultiSI;
L : LongInt;
R : Mu1Digit;
Fini : Boolean;
begin
if B.ZTest then begin {B = 0}
if P.S then begin
MuWriteErr('Cannot raise zero to a negative power');
end
else if P.ZTest then begin {P = 0}
MuWriteErr('Cannot raise zero to the zero power');
end;
Clear; Exit;
end;
if (P.S) and ((B.N > 1) or (B.V^[0] > 1)) then begin { (>1) ** -P}
Clear; Exit;
end;
if (B.N = 1) and (B.V^[0] = 1) then begin {B = +/-1}
L:= Round( P.V^[0]);
S:= B.S and ((L Mod 2) = 1);
N:= 1; V^[0]:= 1; Exit;
end;
Fini:= False;
New( BL, Init( Self.M)); BL^.SetTo(B);
New( PL, Init( P.N)); PL^.SetTo(P);
SetTo1(1);
repeat
L:= Round( PL^.V^[0]);
if (L Mod 2) = 1 then begin
Self.Mul( BL^, Self);
Self.ModMB;
end;
IpDiv1(2, PL^, R);
if PL^.ZTest then Fini:= True
else begin
BL^.Mul( BL^, BL^);
BL^.ModMB;
end;
if MuAbort then begin
Clear;
Fini:= True;
end;
until Fini;
Dispose( PL, Done);
Dispose( BL, Done);
end; {MultiSI.PowMB}
{--------------------------------------}
procedure MultiSI.RPowMB( var P : MultiSI); {Self = (Self ** P) Mod MuMB}
{P may have the same address in memory as Self}
{P is not changed unless it shares memory with Self}
{Sets MuErr True if overflow or error}
begin
PowMB( Self, P);
end; {MultiSI.RPowMB}
{--------------------------------------}
procedure MultiSI.GCD( var A, B : MultiSI);{Self = Greatest common divisor A, B}
{A, B are not modified unless they share memory with Self}
{Will write to standard output if MuErrRep is True}
var
AL, BL : ^MultiSI;
I, NN : Integer;
Fini : Boolean;
begin
New( AL, Init( A.N)); AL^.SetTo(A);
New( BL, Init( B.N)); BL^.SetTo(B);
Fini:= False;
AL^.S:= False; BL^.S:= False;
if AL^.ZTest then begin Self.SetTo( BL^); Fini:= True; end;
if BL^.ZTest then begin Self.SetTo( AL^); Fini:= True; end;
NN:= 0;
{ if MuErrRep and Not Fini then for I:= 0 to Echo do WriteLn( OutP[I]^); }
while Not Fini do begin
Inc( NN);
if Odd( NN) then begin
AL^.Modu( AL^, BL^);
if MuErrRep then begin
for I:= 0 to Echo do begin
Write( OutP[I]^, NN, ' '); AL^.WritLn( OutP[I]^);
end;
end;
if AL^.ZTest then begin Self.SetTo( BL^); Fini:= True; end;
end
else begin
BL^.Modu( BL^, AL^);
if MuErrRep then begin
for I:= 0 to Echo do begin
Write( OutP[I]^, NN, ' '); BL^.WritLn( OutP[I]^);
end;
end;
if BL^.ZTest then begin Self.SetTo( AL^); Fini:= True; end;
end;
end;
Dispose( AL, Done);
Dispose( BL, Done);
end; {MultiSI.GCD}
{--------------------------------------}
procedure MultiSI.RGCD( var A: MultiSI); {Self=Greatest common divisor A, Self}
{A is not modified unless it shares memory with Self}
{Will write to standard output if MuErrRep is True}
begin
GCD(A, Self);
end; {MultiSI.RGCD}
{--------------------------------------}
procedure MultiSI.FacMB( var X: MultiSI); {Self = (X !) Mod MuMB = 1*2*3*...*X}
{X may have the same address in memory as Self}
{X is not changed unless it shares memory with Self}
{Sets MuErr True if overflow or error}
var
XL : ^MultiSI;
NN : Double;
begin
if X.S then begin
MuWriteErr('Cannot take factorial of number < zero');
Clear; Exit;
end;
if X.N > 2 then begin
MuWriteErr('Number too large for factorial function');
Clear; Exit;
end;
New( XL, Init( X.N)); XL^.SetTo(X);
Self.SetTo1(1);
XL^.GetD( NN);
while NN > 1 do begin
Self.Mul( XL^, Self);
Self.ModMB;
if MuAbort then begin
Dispose( XL, Done);
Clear; Exit;
end;
NN:= NN - 1;
XL^.SetToD( NN);
end;
Dispose( XL, Done);
end; {MultiSI.FacMB}
{--------------------------------------}
procedure MultiSI.RFacMB; {Self = (Self !) Mod MuMB = 1*2*3*...*X}
{Sets MuErr True if overflow or error}
begin
FacMB( Self);
end; {MultiSI.RFacMB}
{--------------------------------------}
procedure MultiSI.SqRtRem( var X, R : MultiSI); {Self = SqRt(X), R = Rem}
{X is not changed, X is moved to R and then R is "divided"}
{in place to give the SqRt in Self and a remainder in R, it is ok for X and R}
{or X and Self to have the same location in memory, but then X will be changed}
{Self and R may not have the same location in memory. Sets MuErr True if error}
var
D0, QH : Mu1Digit;
T, T2, D4, K : Mu2Digit;
I, J, RI0, DI0, RI, DI, IJ : Integer;
begin
if Self.V = R.V then begin
MuWriteErr(
'Cannot set same location to both square root and remainder, continuing...');
Exit;
end;
R.SetTo(X);
MultiSI.CLear;
if R.S then begin
MuWriteErr('Cannot take square root of negative number, continuing...');
R.Clear; Exit;
end;
if R.N < 4 then begin
for I:= R.N to 3 do R.V^[I]:= 0;
R.N:= 4;
end;
if Odd( R.N) then begin
R.V^[ R.N]:= 0;
R.N:= R.N + 1;
end;
Self.N:= R.N div 2 + 1;
T:= 0;
for I:= 1 to 4 do T:= T * Base + R.V^[ R.N - I];
T2:= Int( SqRt(T));
repeat
D0:= Int( T2 / Base);
QH:= 1 + T2 - D0 * Base; {+1 for safety}
T:= R.V^[ R.N - 1] * Base + R.V^[ R.N - 2] - D0 * D0;
if T < 0 then T2:= T2 - 1;
until T >= 0;
K:= Int(T / Base);
R.V^[ R.N - 2]:= T - K * Base;
R.V^[ R.N - 1]:= K;
if Self.N >= 4 then Self.V^[ Self.N - 4]:= 0;
Self.V^[ Self.N - 3]:= QH;
T:= 2 * D0;
K:= Int(T / Base);
Self.V^[ Self.N - 2]:= T - K * Base;
Self.V^[ Self.N - 1]:= K;
KeyHit:= False;
for J:= 2 to R.N div 2 do begin
K:= Base; RI0:= R.N - J - J; DI0:= Self.N - J - 1;
RI:= RI0; DI:= DI0; IJ:= RI0 + J;
while RI <= IJ do begin {Multiply and subtract}
T:= R.V^[ RI] - QH * Self.V^[ DI] + K + BSMB; {+ BaseSq - Base}
K:= Int(T / Base);
T:= T - K * Base;
R.V^[ RI]:= T;
Inc( RI); Inc( DI);
end;
T:= R.V^[ RI] + K + BSMB; {+ BaseSq - Base}
K:= Int(T / Base);
R.V^[ RI]:= T - K * Base;
while K = MaxDigit do begin {Test remainder}
{WriteLn('MuSqRt: Doing an add back'); .Diag for add back test}
QH:= QH - 1; {Add back}
K:= QH; RI:= RI0; DI:= DI0;
while RI <= IJ do begin
T:= R.V^[ RI] + Self.V^[ DI] + K;
K:= Int(T / Base);
R.V^[ RI]:= T - K * Base;
Inc( RI); Inc( DI);
end;
T:= R.V^[ RI] + K;
K:= Int(T / Base);
R.V^[ RI]:= T - K * Base;
K:= K + MaxDigit;
Self.V^[ DI0]:= QH;
end;
I:= DI0; IJ:= I + J; K:= QH;
while (I <= IJ) do begin
T:= Self.V^[I] + K; {Carry to next super digit}
K:= Int(T / Base);
Self.V^[I]:= T - K * Base;
if K = 0 then I:= IJ; {Break out of loop}
Inc(I);
end;
if J < R.N div 2 then begin
T:= 0;
for I:= 0 to 4 do begin
T:= T * Base + R.V^[ R.N - J - I];
end;
D4:= 0;
for I:= 1 to 4 do begin
D4:= D4 * Base + Self.V^[ Self.N - I];
end;
QH:= 1 + Int(T / D4);
Self.V^[ Self.N - J - 2]:= QH;
end;
MuInterrupt;
if MuAbort then begin
Self.Clear; R.Clear; Exit;
end;
if KeyHit then begin
for I:= 0 to Echo do
WriteLn( OutP[I]^, 'Integer Square Root: ',
Trunc( (100.0 * J) / (R.N / 2)), ' Percent done');
KeyHit:= False;
end;
end;
R.N:= R.N div 2 + 1;
R.Norm;
Self.Norm;
IpDiv1(2, Self, QH);
end; {MultiSI.SqRtRem}
{--------------------------------------}
procedure MultiSI.RSqRtRem( var R : MultiSI); {Self = SqRt( Self), R = Rem}
{Self is moved to R and then R is "divided" in place to give the SqRt in Self}
{and a remainder in R, Self and R may not have the same location in memory}
{Sets MuErr True if error}
begin
SqRtRem( Self, R);
end; {MultiSI.RSqRtRem}
{--------------------------------------}
procedure MultiSI.SqRoot( var X : MultiSI); {Self = SqRt(X)}
{X is not changed, it is ok for X and Self to have the same location in memory}
{but then X will be changed. Sets MuErr True if error}
var
RL : ^MultiSI;
begin
New( RL, Init( X.N));
SqRtRem(X, RL^);
Dispose( RL, Done);
end; {MultiSI.SqRoot}
{--------------------------------------}
procedure MultiSI.RSqRt; {Self = SqRt( Self)}
{Sets MuErr True if error}
begin
SqRoot( Self);
end; {MultiSI.RSqRt}
{------End of MultiSI's methods--------}
{--------------------------------------}
{ End of method implementation }
{--------------------------------------}
{--------------------------------------}
{ Other services }
{--------------------------------------}
{--------------------------------------}
procedure ShiftUp( var St : String); {Shift string to upper case}
var
I : Integer;
begin
for I:= 1 to Length( St) do St[I]:= UpCase( St[I]);
end; {ShiftUp}
{--------------------------------------}
procedure MuWriteErr( St : String); {Write error statement and set error flag}
{Allows St to be a literal string}
var
I : Integer;
begin
MuErr:= True;
if MuErrRep then
for I:= 0 to Echo do begin
WriteLn( OutP[I]^, St); WriteLn( OutP[I]^);
end;
end; {MuWriteErr}
{--------------------------------------}
procedure ReadLInt( Mess : String; Min, Max, Nom : LongInt;
var II : LongInt); {Read in a long integer from keyboard}
var
St : String[ 255];
Stat : Integer;
LI : LongInt;
I : Integer;
begin
repeat
repeat
for I:= 0 to Echo do begin
WriteLn( OutP[I]^, Mess);
Write( OutP[I]^, ' [', Min, ', ', Max, '] (ENTER => ', Nom, '): ');
end;
ReadLn( St);
for I:= 1 to Echo do WriteLn( OutP[I]^, St);
until IOResult = 0;
Val( St, LI, Stat);
until ((Stat = 0) and (LI >= Min) and (LI <= Max)) or (Length( St) = 0);
if Length( St) = 0 then LI:= Nom;
II:= LI;
for I:= 0 to Echo do begin
WriteLn( OutP[I]^, 'Input = ', II);
WriteLn( OutP[I]^);
end;
end; {ReadLInt}
{--------------------------------------}
procedure ReadInt( Mess : String; Min, Max, Nom : Integer;
var II : Integer); {Read in an integer from keyboard}
var
St : String[ 255];
Stat : Integer;
LI : LongInt;
I : Integer;
begin
repeat
repeat
for I:= 0 to Echo do begin
WriteLn( OutP[I]^, Mess);
Write( OutP[I]^, ' [', Min, ', ', Max, '] (ENTER => ', Nom, '): ');
end;
ReadLn( St);
for I:= 1 to Echo do WriteLn( OutP[I]^, St);
until IOResult = 0;
Val( St, LI, Stat);
until ((Stat = 0) and (LI >= Min) and (LI <= Max)) or (Length( St) = 0);
if Length( St) = 0 then LI:= Nom;
II:= LI;
for I:= 0 to Echo do begin
WriteLn( OutP[I]^, 'Input = ', II);
WriteLn( OutP[I]^);
end;
end; {ReadInt}
{--------------------------------------}
procedure MuSetMMax( NRegs : Integer); {Set MMax}
var
Max : LongInt;
Percent : Integer;
I : Integer;
begin
Max:= MemAvail;
for I:= 0 to Echo do
WriteLn( OutP[I]^, 'MemAvail = ', Max);
ReadInt('Input % of available memory to use:', 0, 100, 100, Percent);
Max:= ((Max - 256) * Percent) div (100 * NRegs); {Max per register}
MMax:= (Max - SizeOf( MultiSI)) div SizeOf( Mu1Digit) - 1;
if MMax > MuNMax then MMax:= MuNMax;
if MMax < 5 then MMax:= 5;
end; {MuSetMMax}
{--------------------------------------}
procedure MuInterrupt; {Test for ESC key pressed to abort operation}
{MuAbort set TRUE if ESC pressed twice, unchanged if no ESC or ESC, SPACE}
const
Esc = Chr( 27); {ESCAPE}
Ret = Chr( 13); {RETURN}
var
I : Integer;
Ch : Char;
begin
If not Keypressed then Exit;
while Keypressed do begin
Ch:= ReadKey;
end;
KeyHit:= True; KeyCh:= Ch;
if Trace > 0 then begin
for I:= 0 to Echo do
WriteLn( OutP[I]^, '<', Tracn, ' ', Trace, '>');
Trace:= 0;
end;
if (Ch <> Esc) or MuAbort then Exit;
for I:= 0 to Echo do begin
WriteLn( OutP[I]^, '*** INTERRUPT: To Continue Press RETURN Key;');
WriteLn( OutP[I]^, 'To Abort Computation Press ESCAPE Key.');
WriteLn( OutP[I]^);
KeyHit:= False;
end;
repeat
Ch:= ReadKey;
until (Ch = Esc) or (Ch = Ret);
if Ch = Ret then for I:= 0 to Echo do begin
WriteLn( OutP[I]^, 'Continuing...'); WriteLn( OutP[I]^);
end;
if Ch = Esc then begin
MuAbort:= True;
for I:= 0 to Echo do begin
WriteLn( OutP[I]^, 'Computation aborted by operator!');
WriteLn( OutP[I]^);
end;
end;
end; {MuInterrupt}
{---------------------------------------}
function DosClock : Double; {Get the value of the Dos clock in total seconds}
{Only good to 0.01 seconds, must call earlier once each day}
var
DC : Double; {Local value of DosClock}
Regs : Registers; {Registers for Dos calls defined in Turbo Pascal}
{ Regs : record
case Integer of
1 : (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags : Word);
2 : (AL, AH, BL, BH, CL, CH, DL, DH : Byte);
end;
}
begin
Regs.AH:= $2C;
MsDos( Regs);
with Regs do
DC:= DosDays * 86400.0 + CH * 3600.0 + CL * 60.0 + DH + DL / 100.0;
if DC < DosClockP then begin
Inc( DosDays);
DC:= DC + 86400.0;
end;
DosClockP:= DC;
DosClock := DC;
end; {DosClock}
{--------------------------------------}
procedure Diag( Mess : String); {Output a diagnostic message with delta times}
var
EI : Integer;
Del0 : Double; {Total time from TV0}
Del1 : Double; {Delta time from last Diag call}
begin
if DiagOn then begin
TV1:= TV2; TV2:= DosClock;
Del0:= TV2 - TV0;
Del1:= TV2 - TV1;
for EI:= 0 to Echo do
WriteLn( OutP[ EI]^, 'T = ', Del0:0:2,
' DT = ', Del1:0:2, ' sec. ',Mess);
end;
end; {Diag}
{--------End of other services---------}
{--------------------------------------}
{ Initialization section }
{--------------------------------------}
{Initialize Multi-precision package}
{Input: MuDMax, MuNMax}
{Output: Base, BaseSq, MaxDigit, BSMB, OutP}
{Initialize: MuDpG=5, MuLenD=21, MuErr=False, MuErrRep=True, MuAbort=False,}
{Echo=0, MMax=MuNMax, TracN=0, Trace=0, DiagOn=False, TV0=TV1=TV2=DosClock}
var I : Integer;
begin
Base:= 10;
for I:= 2 to MuDMax do Base:= 10 * Base;
MaxDigit := Base - 1;
BaseSq := Base * Base;
BSMB := BaseSq - Base;
MuDpG := 5;
MuLenD := 21;
MuErr := False;
MuErrRep := True;
MuAbort := False;
KeyHit := False;
KeyCh := ' ';
Echo := 0;
OutP[0] := @Output; OutP[1]:= @Lst;
MMax := MuNMax;
TracN := 0;
Trace := 0;
DiagOn := False;
DosClockP:= 86400.0;
DosDays := 0;
TV0 := DosClock;
TV1 := TV0;
TV2 := TV1;
MuMaxW := 65;
MuTot := 0;
end. {MultiIDO unit init}
Revisions made -
--------
Changed line in procedure MultiSI.Value from:
While St[J] = ' ' do J:= J + J;
to:
While St[J] = ' ' do Inc(J); { HJS 91/04/24, 91/09/24 }
--------
Added procedures SetToEx and GetEx { HJS 91/05/02 and 91/05/04 }
--------
Added test of KeyHit in SqRtRem { HJS 91/08/17 }
--------
Added MuMaxW and MuTot to global vars and MultiSI.Writ { HJS 92/02/07 }
--------
{End of file MultiID.Pas ***************************************************}