[Back to NUMBERS SWAG index] [Back to Main SWAG index] [Original]
Unit LongNum;
{
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
ÛÛÛÝÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÞÛÛÛ±±
ÛÛÛÝÛÛ ÛÛÞÛÛÛ±±
ÛÛÛÝÛÛ Numbers with up to 255 digits ÛÛÞÛÛÛ±±
ÛÛÛÝÛÛ -- New functions and bug fixes -- ÛÛÞÛÛÛ±±
ÛÛÛÝÛÛ ÛÛÞÛÛÛ±±
ÛÛÛÝÛÛ Aleksandar Dlabac ÛÛÞÛÛÛ±±
ÛÛÛÝÛÛ (C) 1997. Dlabac Bros. Company ÛÛÞÛÛÛ±±
ÛÛÛÝÛÛ ------------------------------ ÛÛÞÛÛÛ±±
ÛÛÛÝÛÛ adlabac@urcpg.urc.cg.ac.yu ÛÛÞÛÛÛ±±
ÛÛÛÝÛÛ adlabac@urcpg.pmf.cg.ac.yu ÛÛÞÛÛÛ±±
ÛÛÛÝÛÛ ÛÛÞÛÛÛ±±
ÛÛÛÝßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÞÛÛÛ±±
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ±±
±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
}
{
This program enables use of a very long signed integer numbers - up to
255 digits. Numbers are in fact strings, so they can be easily writed on
screen/file/printer.
}
Interface
Function LongNumError : Boolean;
{ Returns the status of last operations performed. If there was an error
in calculations (overflow, for example), since LongNumError previous
call, True will be returned. }
Function MakeLong (Number:longint) : string;
{ Converts longint number to string. }
Function MakeInt (Number:string) : longint;
{ Converts long number to longint, if possible. }
Function FormatLongNumber (Number:string;Digits:byte) : string;
{ Formats long number so it will have given number of digits. If number of
digits is zero the number will be represented with as less as possible
digits. Otherwise, if number of digits is smaller than number size,
LongNumError will return True. }
Function Neg (A:string) : string;
{ Returns -A. }
Function Sgn (A:string) : shortint;
{ Returns Signum (A): 1 if A>0, 0 if A=0, -1 if A<0. }
Function Add (A,B:string) : string;
{ Returns A+B. }
Function Subtract (A,B:string) : string;
{ Returns A-B. }
Function Multiple (A,B:string) : string;
{ Returns A*B. }
Function Divide (A,B:string;var Remainder:string) : string;
{ Returns A/B. Remainder is division remaider. }
Function Power (A:string;B:byte) : string;
{ Returns A^B. }
Function Square (A:string) : string;
{ Returns A^2. }
Function SquareRoot (A:string) : string;
{ Returns Sqrt (A). If negative value is given, square root of absolute
value will be returned, and LongNumError will return True. }
Function LongToHex (A:string) : string;
{ Returns hexadecimal value of A. }
Function HexToLong (A:string) : string;
{ Returns decimal value of A, where A is hexadecimal value. }
Function Equal (A,B:string) : Boolean;
{ Returns True if A=B. }
Function Greater (A,B:string) : Boolean;
{ Returns True if A>B. }
Function GreaterOrEqual (A,B:string) : Boolean;
{ Returns True if A>=B. }
Implementation
Var LongNumErrorFlag : Boolean;
Function LongNumError : Boolean;
Var Temp : Boolean;
Begin
Temp:=LongNumErrorFlag;
LongNumErrorFlag:=False;
LongnumError:=Temp
End;
Function Dgt (C:char) : byte;
Var Temp : byte;
Begin
Temp:=0;
If C in ['1'..'9'] then
Temp:=Ord (C)-48;
If not (C in ['-',' ','0'..'9']) then
LongNumErrorFlag:=True;
Dgt:=Temp
End;
Function MakeLong (Number:longint) : string;
Var Temp : string;
Begin
Str (Number,Temp);
MakeLong:=Temp
End;
Function MakeInt (Number:string) : longint;
Var Temp : longint;
I : byte;
Flag : Boolean;
Begin
Flag:=(Sgn (Subtract (MakeLong (2147483647),Number))=-1) or
(Sgn (Subtract (Number,MakeLong (-2147483647)))=-1) or (Number='');
Temp:=0;
If Flag then
LongNumErrorFlag:=True
else
Begin
For I:=1 to Length (Number) do
Temp:=Temp*10+Dgt (Number [I]);
Temp:=Temp*Sgn (Number);
End;
MakeInt:=Temp
End;
Function FormatLongNumber (Number:string;Digits:byte) : string;
Var I : byte;
Sign, Temp : string;
Begin
Temp:=Number;
I:=1;
Sign:='';
Repeat
While (I<Length (Temp)) and (Temp [I]=' ') do
Inc (I);
While (I<Length (Temp)) and (Temp [I]='0') do
Begin
Temp [I]:=' ';
Inc (I)
End;
If (I<Length (Temp)) and (Temp [I]='-') then
Begin
Sign:='-';
Temp [I]:=' '
End;
Until (I>=Length (Temp)) or (Temp [I] in ['1'..'9','A'..'F']);
While (Length (Temp)>0) and (Temp [1]=' ') do
Temp:=Copy (Temp,2,Length (Temp)-1);
If Temp='' then
Temp:='0';
If Temp<>'0' then
Temp:=Sign+Temp;
If Digits>0 then
Begin
While Length (Temp)<Digits do
Temp:=' '+Temp;
If (Digits<Length (Temp)) and (Temp [Length (Temp)-Digits]<>' ') then
LongNumErrorFlag:=True;
Temp:=Copy (Temp,Length (Temp)-Digits+1,Digits)
End;
FormatLongNumber:=Temp
End;
Function Neg (A:string) : string;
Var Temp : string;
Begin
Temp:=FormatLongNumber (A,0);
If Temp [1]='-' then
Temp:=Copy (Temp,2,Length (Temp)-1)
else
If Length (Temp)<255 then
Temp:='-'+Temp
else
LongNumErrorFlag:=True;
Neg:=Temp
End;
Function Sgn (A:string) : shortint;
Var I : byte;
Temp : shortint;
S : string;
Begin
S:=FormatLongNumber (A,0);
Case S [1] of
'-' : Temp:=-1;
'0' : Temp:=0;
else Temp:=1
End;
Sgn:=Temp
End;
Function Add (A,B:string) : string;
Var Sign, Factor, SgnA, SgnB, N : shortint;
Transf, Sub, I : byte;
N1, N2, Temp : string;
Begin
SgnA:=Sgn (A);
SgnB:=Sgn (B);
If SgnA*SgnB=0 then
Begin
If Sgn (A)=0 then
Temp:=B
else
Temp:=A
End
else
Begin
If SgnA=-1 then
N1:=Neg (A)
else
N1:=A;
If SgnB=-1 then
N2:=Neg (B)
else
N2:=B;
While Length (N1)<Length (N2) do
N1:=' '+N1;
While Length (N2)<Length (N1) do
N2:=' '+N2;
If SgnA*SgnB>0 then
Begin
Sign:=SgnA;
Factor:=1;
End
else
Begin
If N1=N2 then
Sign:=1
else
Begin
If N1>N2 then
Sign:=SgnA
else
Begin
Sign:=SgnB;
Temp:=N1;
N1:=N2;
N2:=Temp
End
End;
Factor:=-1
End;
Temp:='';
Transf:=0;
Sub:=0;
For I:=Length (N1) downto 1 do
Begin
N:=Transf+(10+Dgt (N1 [I])-Sub) mod 10+Factor*Dgt (N2 [I]);
Transf:=0;
If Dgt (N1 [I])-Sub<0 then
Sub:=1
else
Sub:=0;
If N<0 then
Begin
Sub:=1;
Inc (N,10)
End
else
If N>=10 then
Begin
Transf:=1;
Dec (N,10)
End;
Temp:=Chr (N+48)+Temp;
End;
If ((Length (Temp)=255) and (Transf>0)) or (Sub>0) then
LongNumErrorFlag:=True
else
Begin
If Transf>0 then
Temp:=Chr (Transf+48)+Temp;
If Sign=-1 then
Temp:=Neg (Temp)
End
End;
Temp:=FormatLongNumber (Temp,0);
Add:=Temp
End;
Function Subtract (A,B:string) : string;
Var Temp : string;
Begin
Subtract:=Add (A,Neg (B))
End;
Function Multiple (A,B:string) : string;
Var Sign, SgnA, SgnB, N : shortint;
I, J, D, Transf : byte;
N1, N2, Temp, S : string;
Begin
SgnA:=Sgn (A);
SgnB:=Sgn (B);
Sign:=SgnA*SgnB;
If SgnA=-1 then
N1:=Neg (A)
else
N1:=A;
If SgnB=-1 then
N2:=Neg (B)
else
N2:=B;
If Sign=0 then
Temp:='0'
else
Begin
N1:=FormatLongNumber (N1,0);
N2:=FormatLongNumber (N2,0);
Temp:='0';
For J:=Length (N2) downto 1 do
Begin
D:=Dgt (N2 [J]);
Transf:=0;
S:='';
For I:=1 to Length (N2)-J do
S:=S+'0';
For I:=Length (N1) downto 1 do
Begin
N:=Transf+D*Dgt (N1 [I]);
If Length (S)=255 then
LongNumErrorFlag:=True;
S:=Chr (N mod 10+48)+S;
Transf:=N div 10
End;
If Transf>0 then
If Length (S)=255 then
LongNumErrorFlag:=True
else
S:=Chr (Transf+48)+S;
Temp:=Add (Temp,S)
End
End;
If Sign=-1 then
Temp:=Neg (Temp);
Temp:=FormatLongNumber (Temp,0);
Multiple:=Temp
End;
Function Divide (A,B:string;var Remainder:string) : string;
Var Sign, SgnA, SgnB : shortint;
I, J : byte;
N1, N2, Temp, S1, S2 : string;
Begin
SgnA:=Sgn (A);
SgnB:=Sgn (B);
Sign:=SgnA*SgnB;
If SgnA=-1 then
N1:=Neg (A)
else
N1:=A;
If SgnB=-1 then
N2:=Neg (B)
else
N2:=B;
N1:=FormatLongNumber (N1,0);
N2:=FormatLongNumber (N2,0);
If not GreaterOrEqual (N1,N2) then
Begin
Temp:='0';
If SgnA=-1 then
Remainder:=Neg (N1)
else
Remainder:=N1
End
else
Begin
Temp:='';
S1:=N1;
For I:=1 to Length (N1)-Length (N2)+1 do
Begin
S2:=Copy (S1,1,I+Length (N2)-1);
J:=9;
While Greater (Multiple (N2,Chr (J+48)),S2) do
Dec (J);
Temp:=Temp+Chr (J+48);
S1:=Subtract (S2,Multiple (N2,Chr (J+48)))+Copy (S1,I+Length (N2),Length (S1)-I-Length (N2)+1);
While Length (S1)<Length (N1) do
S1:=' '+S1
End;
If SgnA=-1 then
Remainder:=Neg (Subtract (N1,Multiple (N2,Temp)))
else
Remainder:=Subtract (N1,Multiple (N2,Temp));
End;
If Sign=-1 then
Temp:=Neg (Temp);
Temp:=FormatLongNumber (Temp,0);
Divide:=Temp
End;
Function Power (A:string;B:byte) : string;
Var I : byte;
Temp : string;
Error : Boolean;
Begin
Error:=False;
Temp:='1';
For I:=1 to B do
Temp:=Multiple (Temp,A);
Temp:=FormatLongNumber (Temp,0);
Power:=Temp
End;
Function Square (A:string) : string;
Begin
Square:=Multiple (A,A)
End;
Function SquareRoot (A:string) : string;
Var I : byte;
J : char;
N, Temp, S1, S2, Remainder : string;
Begin
N:=FormatLongNumber (A,0);
If Sgn (N)=-1 then
Begin
LongNumErrorFlag:=True;
N:=Neg (A)
End;
If Length (N) mod 2=1 then
Begin
S1:=' '+N [1];
I:=2
End
else
Begin
S1:=N [1]+N [2];
I:=3
End;
Temp:=Chr (Trunc (Sqrt (MakeInt (S1)))+48);
Remainder:=Subtract (S1,Square (Temp));
While I<Length (N) do
Begin
S1:=Remainder+N [I]+N [I+1];
J:='9';
S2:=Multiple (Temp,'2');
While Greater (Multiple (S2+J,J),S1) do
Dec (J);
Temp:=Temp+J;
Remainder:=Subtract (S1,Multiple (S2+J,J));
Inc (I,2)
End;
SquareRoot:=Temp
End;
Function LongToHex (A:string) : string;
Const HexDigit : array [0..15] of char =
('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
Var SgnA : shortint;
Temp, N, Remainder : string;
Begin
Temp:='';
SgnA:=Sgn (A);
If SgnA=-1 then
N:=Neg (A)
else
N:=FormatLongNumber (A,0);
Repeat
N:=Divide (N,'16',Remainder);
Temp:=HexDigit [MakeInt (Remainder)]+Temp;
Until N='0';
If SgnA=-1 then
Temp:='-'+Temp;
LongtoHex:=Temp
End;
Function HexToLong (A:string) : string;
Var SgnA : shortint;
I : byte;
N, Temp, S1, S2 : string;
Begin
Temp:='';
S1:='1';
SgnA:=Sgn (A);
If SgnA=-1 then
N:=Neg (A)
else
N:=FormatLongNumber (A,0);
For I:=Length (N) downto 1 do
Begin
If N [I] in ['0'..'9'] then
S2:=N [I]
else
If UpCase (N [I]) in ['A'..'F'] then
S2:='1'+Chr (Ord (N [I])-17)
else
LongNumErrorFlag:=True;
Temp:=Add (Temp,Multiple (S1,S2));
S1:=Multiple (S1,'16')
End;
If SgnA=-1 then
Temp:='-'+Temp;
HexToLong:=Temp
End;
Function Equal (A,B:string) : Boolean;
Begin
Equal:=Sgn (Subtract (A,B))=0
End;
Function Greater (A,B:string) : Boolean;
Begin
Greater:=Sgn (Subtract (A,B))>0
End;
Function GreaterOrEqual (A,B:string) : Boolean;
Begin
GreaterOrEqual:=Sgn (Subtract (A,B))>=0
End;
Begin
LongNumErrorFlag:=False
End.
{ ---------------------- Demo program ---------------------- }
Program LongTest;
Uses Crt, LongNum;
Var L : longint;
S1, S2, Remainder : string;
Begin
ClrScr;
S1:=MakeLong (-198371298);
If LongNumError then
Writeln ('Error in calculations.')
else
Write (S1);
L:=MakeInt (S1);
If LongNumError then
Writeln ('Error in calculations.')
else
Writeln (' = ',L);
Writeln;
S1:=Add ('1234567890','987654321');
If LongNumError then
Writeln ('Error in calculations.')
else
Writeln ('1234567890 + 987654321 = ',S1);
Writeln;
S1:=Multiple ('-123','456');
If LongNumError then
Writeln ('Error in calculations.')
else
Writeln ('-123 * 456 = ',S1);
Writeln;
S1:=Divide ('12345','-456',Remainder);
If LongNumError then
Writeln ('Error in calculations.')
else
Writeln ('12345 / (-456) = ',S1,' [',Remainder,']');
Writeln;
S1:=Power ('-1234567890',5);
If LongNumError then
Writeln ('Error in calculations.')
else
Writeln ('-1234567890^5 = ',S1);
Writeln;
S1:=Square ('-1234567890');
If LongNumError then
Writeln ('Error in calculations.')
else
Writeln ('-1234567890^2 = ',S1);
Writeln;
S2:=S1;
S1:=SquareRoot (S1);
If LongNumError then
Writeln ('Error in calculations.')
else
Writeln ('Sqrt (',S2,') = ',S1);
Writeln;
S1:=LongToHex ('1234567890987654321');
If LongNumError then
Writeln ('Error in calculations.')
else
Writeln ('1234567890987654321 = ',S1,'H');
Writeln;
S2:=S1;
S1:=HexToLong (S1);
If LongNumError then
Writeln ('Error in calculations.')
else
Writeln (S2,'H = ',S1)
End.
[Back to NUMBERS SWAG index] [Back to Main SWAG index] [Original]