Contributor: ALEXSANDAR DLABAC

 Unit LongNum;
{
             
             ۱
                                                   ۱
                  Numbers with up to 255 digits    ۱
                                                   ۱
                        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. If variable LongNumError is set to True, there was an
  error during calculations/conversions (overflow, for example).
}
   Interface

   Var LongNumError : Boolean;

   Function MakeLong (Number:longint) : string;
   { Converts longint number to string. }

   Function MakeInt (Number:string) : longint;
   { Converts long number to longint, if possible. }

   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 FormatLongNumber (Number:string;Digits:byte) : string;
   { Formats long number so it will have given number of digits. If number of
     digits is smaller than number size, LongNumError will be True. }

   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 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

   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
           LongNumError:=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;
       Begin
         LongNumError:=(Sgn (Subtract (MakeLong (2147483647),Number))=-1) or
                       (Sgn (Subtract (Number,MakeLong (-2147483647)))=-1) or
                       (Number='');
         Temp:=0;
         If not LongNumError then
           Begin
             For I:=1 to Length (Number) do
               Temp:=Temp*10+Dgt (Number [I]);
             Temp:=Temp*Sgn (Number);
           End;
         MakeInt:=Temp
       End;

   Function Neg (A:string) : string;
     Var Temp : string;
       Begin
         LongNumError:=False;
         Temp:=FormatLongNumber (A,0);
         If Temp [1]='-' then
           Temp:=Copy (Temp,2,Length (Temp)-1)
                         else
           If Length (Temp)<255 then
             Temp:='-'+Temp
                                else
             LongNumError:=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 FormatLongNumber (Number:string;Digits:byte) : string;
     Var I    : byte;
         Temp : string;
       Begin
         Temp:=Number;
         I:=1;
         While (I0) and (Temp [1]=' ') do
           Temp:=Copy (Temp,2,Length (Temp)-1);
         If Temp='' then
           Temp:='0';
         If Digits>0 then
           Begin
             While Length (Temp)' ') then
               LongNumError:=True;
             Temp:=Copy (Temp,Length (Temp)-Digits+1,Digits)
           End;
         FormatLongNumber:=Temp;
       End;

   Function Add (A,B:string) : string;
     Var Sign, Factor, SgnA, SgnB, N : shortint;
         Transf, Sub, I              : byte;
         N1, N2, Temp                : string;
         Error                       : Boolean;
       Begin
         Error:=False;
         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)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;
                 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
               Error:=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);
         If Error then
           LongNumError:=True;
         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;
         Error               : Boolean;
       Begin
         Error:=False;
         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);
             If LongNumError then
               Error:=True;
             N2:=FormatLongNumber (N2,0);
             If LongNumError then
               Error:=True;
             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
                       Error:=True;
                     S:=Chr (N mod 10+48)+S;
                     Transf:=N div 10
                   End;
                 If Transf>0 then
                   If Length (S)=255 then
                     Error:=True
                                     else
                     S:=Chr (Transf+48)+S;
                 Temp:=Add (Temp,S);
                 If LongNumError then
                   Error:=True
               End
           End;
         If Sign=-1 then
           Temp:=Neg (Temp);
         Temp:=FormatLongNumber (Temp,0);
         If Error then
           LongNumError:=True;
         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;
         Error                : Boolean;
       Begin
         Error:=False;
         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);
         If LongNumError then
           Error:=True;
         N2:=FormatLongNumber (N2,0);
         If LongNumError then
           Error:=True;
         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)0
     End;

   Function GreaterOrEqual (A,B:string) : Boolean;
     Begin
       GreaterOrEqual:=Sgn (Subtract (A,B))>=0
     End;

   End.

Program LongTest;

  Uses Crt, LongNum;

  Var L            : longint;
      S, Remainder : string;

  Begin
    ClrScr;
    S:=MakeLong (-198371298);
    If LongNumError then
      Writeln ('Error in calculations.')
                    else
      Write (S);
    L:=MakeInt (S);
    If LongNumError then
      Writeln ('Error in calculations.')
                    else
      Writeln (' = ',L);
    Writeln;
    S:=Add ('1234567890','987654321');
    If LongNumError then
      Writeln ('Error in calculations.')
                    else
      Writeln ('1234567890 + 987654321 = ',S);
    Writeln;
    S:=Multiple ('-123','456');
    If LongNumError then
      Writeln ('Error in calculations.')
                    else
      Writeln ('-123 * 456 = ',S);
    Writeln;
    S:=Divide ('12345','-456',Remainder);
    If LongNumError then
      Writeln ('Error in calculations.')
                    else
      Writeln ('12345 / (-456) = ',S,' [',Remainder,']');
    Writeln;
    S:=Power ('-1234567890',5);
    If LongNumError then
      Writeln ('Error in calculations.')
                    else
      Writeln ('-1234567890^5 = ',S)
  End.