<> <> <> <> <<>> DIRECTORY BigCardinals USING [BigAdd, BigCARD, BigCompare, BigDivMod, BigFromBinaryRope, BigFromDecimalRope, BigFromSmall, BigMultiply, BigSubtract, BigToDecimalRope, BigZero, Zero], BigIntegers USING [Sign], IO USING [int, PutFR], Rope USING [Cat, Fetch, ROPE, Substr], SaffronErrorHandling USING [InternalError]; BigIntegersImpl: CEDAR PROGRAM IMPORTS BigCardinals, IO, Rope, SaffronErrorHandling EXPORTS BigIntegers = BEGIN BigINT: TYPE = REF BigINTBody; BigINTBody: PUBLIC TYPE = RECORD [ sign: Sign, absoluteValue: BigCardinals.BigCARD ]; Sign: TYPE = BigIntegers.Sign; BigFromRope: PUBLIC PROC [text: Rope.ROPE, base: [2..36] _ 10] RETURNS [BigINT] ~ BEGIN sign: Sign _ plus; absoluteValue: BigCardinals.BigCARD; SELECT text.Fetch[0] FROM '+ => {text _ text.Substr[1]}; '- => {text _ text.Substr[1]; sign _ minus}; ENDCASE => NULL; SELECT base FROM 2 => {absoluteValue _ BigCardinals.BigFromBinaryRope[text]}; 10 => {absoluteValue _ BigCardinals.BigFromDecimalRope[text]}; ENDCASE => { ERROR SaffronErrorHandling.InternalError[IO.PutFR["Can't parse base %g", IO.int[base]]] }; RETURN[NEW[BigINTBody _ [sign, absoluteValue]]]; END; RopeFromBig: PUBLIC PROC [big: BigINT, base: [2..36] _ 10] RETURNS [Rope.ROPE] ~ BEGIN RETURN[Rope.Cat[ IF big.sign = minus THEN "-" ELSE "", SELECT base FROM 10 => BigCardinals.BigToDecimalRope[big.absoluteValue], ENDCASE => ERROR SaffronErrorHandling.InternalError[IO.PutFR["Can't parse base %g", IO.int[base]]] ]]; END; BigFromSmall: PUBLIC PROC [small: INT] RETURNS [BigINT] ~ BEGIN RETURN[NEW[BigINTBody _ [ sign: IF small >= 0 THEN plus ELSE minus, absoluteValue: BigCardinals.BigFromSmall[ABS[small]] ]]]; END; <> Add: PUBLIC PROC [big1, big2: BigINT] RETURNS [BigINT] ~ BEGIN abs1: BigCardinals.BigCARD = big1.absoluteValue; abs2: BigCardinals.BigCARD = big2.absoluteValue; RETURN[NEW[BigINTBody _ IF big1.sign = big2.sign THEN [big1.sign, BigCardinals.BigAdd[abs1, abs2]] ELSE SELECT BigCardinals.BigCompare[abs1, abs2] FROM less => [big2.sign, BigCardinals.BigSubtract[abs2, abs1]], equal => [plus, BigCardinals.Zero], greater => [big1.sign, BigCardinals.BigSubtract[abs1, abs2]] ENDCASE => ERROR ]]; END; Sub: PUBLIC PROC [big1, big2: BigINT] RETURNS [BigINT] ~ BEGIN abs1: BigCardinals.BigCARD = big1.absoluteValue; abs2: BigCardinals.BigCARD = big2.absoluteValue; RETURN[NEW[BigINTBody _ IF big1.sign # big2.sign THEN [big1.sign, BigCardinals.BigAdd[abs1, abs2]] ELSE SELECT BigCardinals.BigCompare[abs1, abs2] FROM less => [FlipSign[big1.sign], BigCardinals.BigSubtract[abs2, abs1]], equal => [plus, BigCardinals.Zero], greater => [big1.sign, BigCardinals.BigSubtract[abs1, abs2]] ENDCASE => ERROR ]]; END; Mul: PUBLIC PROC [big1, big2: BigINT] RETURNS [BigINT] ~ BEGIN RETURN[NEW[BigINTBody _ [ sign: IF big1.sign = big2.sign THEN plus ELSE minus, absoluteValue: BigCardinals.BigMultiply[big1.absoluteValue, big2.absoluteValue] ]]]; END; Div: PUBLIC PROC [big1, big2: BigINT] RETURNS [BigINT] ~ BEGIN RETURN[NEW[BigINTBody _ [ sign: IF big1.sign = big2.sign THEN plus ELSE minus, absoluteValue: BigCardinals.BigDivMod[big1.absoluteValue, big2.absoluteValue].quo ]]]; END; Mod: PUBLIC PROC [big1, big2: BigINT] RETURNS [BigINT] ~ BEGIN RETURN[NEW[BigINTBody _ [ sign: IF big1.sign = big2.sign THEN plus ELSE minus, absoluteValue: BigCardinals.BigDivMod[big1.absoluteValue, big2.absoluteValue].rem ]]]; END; Neg: PUBLIC PROC [big1: BigINT] RETURNS [BigINT] ~ BEGIN RETURN[IF BigCardinals.BigZero[big1.absoluteValue] THEN big1 ELSE NEW[BigINTBody _ [ sign: FlipSign[big1.sign], absoluteValue: big1.absoluteValue ]]]; END; FlipSign: PROC [sign: Sign] RETURNS [Sign] = INLINE { RETURN[IF sign = plus THEN minus ELSE plus]; }; MultiplySigns: PROC [sign1, sign2: Sign] RETURNS[Sign] = INLINE { RETURN[IF sign1 = sign2 THEN plus ELSE minus]; }; Abs: PUBLIC PROC [big1: BigINT] RETURNS [BigCardinals.BigCARD] ~ BEGIN RETURN [big1.absoluteValue]; END; Sgn: PUBLIC PROC [big1: BigINT] RETURNS [Sign] ~ BEGIN RETURN [big1.sign]; END; BigFromBigCARD: PUBLIC PROC [bc: BigCardinals.BigCARD, sign: Sign] RETURNS [BigINT] ~ BEGIN IF BigCardinals.BigZero[bc] THEN RETURN [NEW[BigINTBody _ [plus, bc]]] ELSE RETURN [NEW[BigINTBody _ [sign, bc]]]; END; END. <<>>