packages feed

language-Modula2-0.1: examples/Modula-2_Libraries/andrea-m2/lib/generic/base3.mod

IMPLEMENTATION MODULE Base3;

(* John Andrea, Nov.18/91 *)
(* This code may be freely used and distributed, it may not be sold. *)

(* for 16 bit machines use max_power of 11 *)
(* for 32 bit machines use max_power of 20 *)

FROM StringOperations IMPORT Length;

CONST
  max_power = 20;

VAR
  power3 :ARRAY [0..max_power] OF CARDINAL;
  max_value, i :CARDINAL;

  (* --------------------------------------------------------- *)
  PROCEDURE Max10() :CARDINAL;
  BEGIN
     RETURN max_value;
  END Max10;

  (* --------------------------------------------------------- *)
  PROCEDURE HowMany3( base10 :CARDINAL ) :CARDINAL;
  (* return the number of base 3 digits needed to represent 'x' *)
  VAR n :CARDINAL;
  BEGIN

     IF base10 < 3 THEN
       n := 1;
     ELSE

       (* find the largest position in the power list *)
       n := 0;
       WHILE base10 >= power3[n] DO
         n := n + 1;
       END;

     END;

     RETURN n;

  END HowMany3;

  (* --------------------------------------------------------- *)
  PROCEDURE ToBase3( base10 :CARDINAL; VAR base3 :ARRAY OF CHAR; VAR ok :BOOLEAN );
  VAR
    n, i, j, k, high :CARDINAL;

  BEGIN

    high := HIGH( base3 );

    IF base10 = 0 THEN
      ok := TRUE;
      base3[0] := '0';
      IF high > 0 THEN base3[1] := 0C; END;
    ELSE

      IF base10 > max_value THEN
        ok := FALSE;
        base3[0] := 0C;
      ELSE

        n := HowMany3( base10 ) - 1;

        IF n > HIGH( base3 ) THEN
          ok := FALSE;
          base3[0] := 0C;
        ELSE

          (* for each of the powers of 3, count their numbers *)
          FOR i := 0 TO n DO
             j := n - i;
             k := 0;
             WHILE base10 >= power3[j] DO
               k      := k + 1;
               base10 := base10 - power3[j];
             END;
             IF k = 0 THEN
               base3[i] := '0';
             ELSIF k = 1 THEN
               base3[i] := '1';
             ELSE
               base3[i] := '2';
             END;
          END;

          IF high > n THEN base3[n+1] := 0C; END;
       END;
      END;
    END;

  END ToBase3;

  (* --------------------------------------------------------- *)
  PROCEDURE FromBase3( base3 :ARRAY OF CHAR; VAR base10 :CARDINAL; VAR ok :BOOLEAN );
  VAR
    i, n, d :CARDINAL;
    c       :CHAR;
  BEGIN
     ok     := TRUE;
     base10 := 0;

     n := Length( base3 );

     i := 0;
     WHILE ( i < n ) & ok DO

       c := base3[i];
       IF c = '0' THEN
         d := 0;
       ELSIF c = '1' THEN
         d := 1;
       ELSIF c = '2' THEN
         d := 2;
       ELSE
         ok := FALSE;  d := 0;
       END;

       base10 := base10 * 3 + d;
       i := i + 1;
     END;

  END FromBase3;

BEGIN

  (* precompute the powers of 3 *)
  power3[0] := 1;
  FOR i := 1 TO max_power DO
     power3[i] := 3 * power3[i-1];
  END;

  max_value := power3[max_power];

END Base3.