home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / Misc / OB3.2D2.DMS / in.adf / Module / BigIntegers.mod < prev    next >
Encoding:
Text File  |  1994-08-05  |  7.2 KB  |  308 lines

  1. (*-------------------------------------------------------------------------*)
  2. (*                                                                         *)
  3. (*  Amiga Oberon Interface Module: BigIntegers        Date: 02-Nov-92      *)
  4. (*                                                                         *)
  5. (*   © 1992 by Fridtjof Siebert                                            *)
  6. (*                                                                         *)
  7. (*-------------------------------------------------------------------------*)
  8.  
  9. MODULE BigIntegers;
  10.  
  11. IMPORT BT * := BasicTypes;
  12.  
  13. TYPE
  14.   BigInteger * = POINTER TO BigIntegerDesc;
  15.   BigIntegerDesc * = RECORD (BT.RINGDesc)
  16.     negative - : BOOLEAN;
  17.     digits   - : POINTER TO ARRAY OF INTEGER;
  18.   END;
  19.  
  20. CONST
  21.  
  22.   MaxDigit * = 1000;
  23.   (*
  24.    * for all i, 0 <= i < LEN(digits^):
  25.    *   0 <= digits[i] < MaxDigit
  26.    *
  27.    * NOTE: 2 * MaxDigit < MAX(INTEGER)
  28.    *
  29.    *)
  30.  
  31.  
  32. PROCEDURE InternalCreate (numDigits: LONGINT): BigInteger;
  33. (*
  34.  * Create new BigInteger with room for numDigits digits.
  35.  *
  36.  *)
  37.  
  38. VAR
  39.   bi: BigInteger;
  40.  
  41. BEGIN
  42.   NEW(bi);
  43.   NEW(bi.digits,numDigits);
  44.   RETURN bi;
  45. END InternalCreate;
  46.  
  47.  
  48. PROCEDURE Create * (init: LONGINT): BigInteger;
  49. (*
  50.  * Create new BigInteger. Set its value to init.
  51.  *
  52.  * require
  53.  *   -MAX(LONGINT) <= init <= MAX(LONGINT)
  54.  *)
  55.  
  56. VAR
  57.   bi: BigInteger;
  58.   neg: BOOLEAN;
  59.  
  60. BEGIN
  61.   IF init<0 THEN
  62.     init := -init;
  63.     neg := TRUE;
  64.   ELSE
  65.     neg := FALSE;
  66.   END;
  67.   IF init<MaxDigit THEN
  68.     bi := InternalCreate(1);
  69.     bi.digits[0] := SHORT(init);
  70.   ELSIF init<MaxDigit*MaxDigit THEN
  71.     bi := InternalCreate(2);
  72.     bi.digits[0] := SHORT(init MOD MaxDigit);
  73.     bi.digits[1] := SHORT(init DIV MaxDigit);
  74.   ELSE
  75.     bi := InternalCreate(3);
  76.     bi.digits[0] := SHORT(init MOD MaxDigit);
  77.     bi.digits[1] := SHORT(init DIV MaxDigit MOD MaxDigit);
  78.     bi.digits[2] := SHORT(init DIV (MaxDigit*MaxDigit));
  79.   END;
  80.   bi.negative := neg;
  81.   RETURN bi;
  82. END Create;
  83.  
  84.  
  85. PROCEDURE (a: BigInteger) Compare * (b: BT.COMPAREABLE): LONGINT;
  86. VAR
  87.   i: LONGINT;
  88. BEGIN
  89.  
  90.   WITH b: BigInteger DO
  91.  
  92.     i := LEN(b.digits^);
  93.     WHILE i>LEN(a.digits^) DO
  94.       DEC(i);
  95.       IF b.digits[i]#0 THEN RETURN 1 END;
  96.     END;
  97.  
  98.     WHILE i>0 DO
  99.       DEC(i);
  100.       IF b.digits[i]#a.digits[i] THEN
  101.         RETURN a.digits[i]-b.digits[i];
  102.       END;
  103.     END;
  104.  
  105.     RETURN 0
  106.  
  107.   END;
  108.  
  109. END Compare;
  110.  
  111.  
  112. PROCEDURE (m: BigInteger) Add * (n: BT.GROUP): BT.GROUP;
  113. VAR
  114.   result,swap: BigInteger;
  115.   len,i: LONGINT;
  116.   carry: BOOLEAN;
  117. BEGIN
  118.   WITH n: BigInteger DO
  119.     IF LEN(m.digits^)<LEN(n.digits^) THEN
  120.       swap := m; m := n; n := swap;
  121.     END;
  122.     len := LEN(m.digits^);
  123.     IF m.digits[len-1] >= MaxDigit DIV 2 THEN
  124.       INC(len)
  125.     END;
  126.     IF (len=LEN(n.digits^)) & (n.digits[len-1] >= MaxDigit DIV 2) THEN
  127.       INC(len)
  128.     END;
  129.     result := InternalCreate(len);
  130.     IF m.negative = n.negative THEN
  131.       result.negative := m.negative;
  132.       carry := FALSE;
  133.       FOR i:=0 TO len-1 DO
  134.         result.digits[i] := 0;
  135.         IF carry THEN
  136.           INC(result.digits[i]);
  137.         END;
  138.         IF i<LEN(m.digits^) THEN INC(result.digits[i],m.digits[i]) END;
  139.         IF i<LEN(n.digits^) THEN INC(result.digits[i],n.digits[i]) END;
  140.         IF result.digits[i] >= MaxDigit THEN
  141.           carry := TRUE;
  142.           DEC(result.digits[i],MaxDigit);
  143.         ELSE
  144.           carry := FALSE;
  145.         END;
  146.       END;
  147.     ELSE
  148.       IF m.negative THEN
  149.         swap := m; m := n; n := swap;
  150.       END;
  151.       carry := FALSE;
  152.       FOR i:=0 TO len-1 DO
  153.         result.digits[i] := 0;
  154.         IF carry THEN
  155.           DEC(result.digits[i]);
  156.         END;
  157.         IF i<LEN(m.digits^) THEN INC(result.digits[i],m.digits[i]) END;
  158.         IF i<LEN(n.digits^) THEN DEC(result.digits[i],n.digits[i]) END;
  159.         IF result.digits[i] < 0 THEN
  160.           carry := TRUE;
  161.           INC(result.digits[i],MaxDigit);
  162.         ELSE
  163.           carry := FALSE;
  164.         END;
  165.       END;
  166.       IF carry THEN
  167.         result.negative := TRUE;
  168.         carry := FALSE;
  169.         FOR i:=0 TO len-1 DO
  170.           result.digits[i] := 0;
  171.           IF carry THEN
  172.             DEC(result.digits[i]);
  173.           END;
  174.           IF i<LEN(m.digits^) THEN DEC(result.digits[i],m.digits[i]) END;
  175.           IF i<LEN(n.digits^) THEN INC(result.digits[i],n.digits[i]) END;
  176.           IF result.digits[i] < 0 THEN
  177.             carry := TRUE;
  178.             INC(result.digits[i],MaxDigit);
  179.           ELSE
  180.             carry := FALSE;
  181.           END;
  182.         END;
  183.       ELSE
  184.         result.negative := FALSE;
  185.       END;
  186.     END;
  187.   END;
  188.   RETURN result;
  189. END Add;
  190.  
  191.  
  192. PROCEDURE (m: BigInteger) Neg * (): BT.GROUP;
  193. VAR
  194.   result: BigInteger;
  195.   i: LONGINT;
  196. BEGIN
  197.   result := InternalCreate(LEN(m.digits^));
  198.   IF result#NIL THEN
  199.     FOR i:=0 TO LEN(m.digits^)-1 DO
  200.       result.digits[i] := m.digits[i];
  201.     END;
  202.     result.negative := ~ m.negative;
  203.   END;
  204.   RETURN result;
  205. END Neg;
  206.  
  207.  
  208. PROCEDURE (m: BigInteger) Norm * (): LONGREAL;
  209. VAR
  210.   result: LONGREAL;
  211.   i: LONGINT;
  212. BEGIN
  213.   result := 0;
  214.   FOR i:=0 TO LEN(m.digits^)-1 DO
  215.     result := 1000*result + m.digits[i];
  216.   END;
  217.   RETURN result;
  218. END Norm;
  219.  
  220.  
  221. PROCEDURE (m: BigInteger) Mul * (n: BT.RING): BT.RING;
  222. VAR
  223.   result: BigInteger;
  224.   len: LONGINT;
  225.   carry: INTEGER;
  226.   zw: LONGINT;
  227.   i,j: LONGINT;
  228. BEGIN
  229.   WITH n: BigInteger DO
  230.     len := LEN(m.digits^) + LEN(n.digits^);
  231.     result := InternalCreate(len);
  232.     IF result#NIL THEN
  233.       result.negative := m.negative # n.negative;
  234.       FOR i := 0 TO LEN(m.digits^)-1 DO
  235.         carry := 0;
  236.         FOR j := 0 TO LEN(n.digits^)-1 DO
  237.           INC(result.digits[i+j],carry);
  238.           carry := 0;
  239.           IF result.digits[i+j] >= MaxDigit THEN
  240.             INC(carry);
  241.             DEC(result.digits[i+j],MaxDigit);
  242.           END;
  243.           zw  := LONG(n.digits[j]) * LONG(m.digits[i]);
  244.           INC(carry,SHORT(zw DIV MaxDigit));
  245.           INC(result.digits[i+j],SHORT(zw MOD MaxDigit));
  246.           IF result.digits[i+j] >= MaxDigit THEN
  247.             INC(carry);
  248.             DEC(result.digits[i+j],MaxDigit);
  249.           END;
  250.         END;
  251.         INC(j,i);
  252.         WHILE j < len DO
  253.           INC(result.digits[j],carry);
  254.           carry := 0;
  255.           IF result.digits[j] >= MaxDigit THEN
  256.             carry := 1;
  257.             DEC(result.digits[j],MaxDigit);
  258.           END;
  259.           INC(j);
  260.         END;
  261.       END;
  262.     END;
  263.     RETURN result;
  264.   END;
  265. END Mul;
  266.  
  267.  
  268. PROCEDURE (n: BigInteger) ConvertToString * (): BT.DynString;
  269. (*
  270.  * Allocates space for to^ and converts n to an ASCII-String
  271.  *)
  272. VAR
  273.   i,off: LONGINT;
  274.   to: BT.DynString;
  275. BEGIN
  276.   i := LEN(n.digits^);
  277.   WHILE (i>0) & (n.digits[i-1]=0) DO DEC(i) END;
  278.   NEW(to,i * 3 + 1);
  279.   off := 0;
  280.   DEC(i);
  281.   to[LEN(to^)-3*i-3   ] := CHR(ORD("0") + n.digits[i] DIV 100 MOD 10);
  282.   IF to[LEN(to^)-3*i-3]="0" THEN INC(off) END;
  283.   to[LEN(to^)-3*i-2-off] := CHR(ORD("0") + n.digits[i] DIV  10 MOD 10);
  284.   IF (off>0) & (to[LEN(to^)-3*i-2-off]="0") THEN INC(off) END;
  285.   to[LEN(to^)-3*i-1-off] := CHR(ORD("0") + n.digits[i]         MOD 10);
  286.   WHILE i>0 DO
  287.     DEC(i);
  288.     to[LEN(to^)-3*i-3-off] := CHR(ORD("0") + n.digits[i] DIV 100 MOD 10);
  289.     to[LEN(to^)-3*i-2-off] := CHR(ORD("0") + n.digits[i] DIV  10 MOD 10);
  290.     to[LEN(to^)-3*i-1-off] := CHR(ORD("0") + n.digits[i]         MOD 10);
  291.   END;
  292.   IF n.negative THEN
  293.     to[0] := "-"
  294.   ELSE
  295.     to[0] := " ";
  296.   END;
  297.   RETURN to;
  298. END ConvertToString;
  299.  
  300.  
  301. END BigIntegers.
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.