GENERIC MODULEIntegerBasic ();
Arithmetic for Modula-3, see doc for details
IMPORT Word AS W, Arithmetic AS Arith; <* UNUSED *> CONST Module = "IntegerBasic."; PROCEDUREKapil Hari Paranjape: Some lectures on number theory, elliptic curves and cryptology, chapter 2: Greatest common divisor, https://www.imsc.ernet.in/~kapil/crypto/notes/node8.htmlAdd (x, y: T; ): T = BEGIN RETURN x + y END Add; PROCEDURESub (x, y: T; ): T = BEGIN RETURN x - y END Sub; PROCEDURENeg (x: T; ): T = BEGIN RETURN -x END Neg; PROCEDUREConj (x: T; ): T = BEGIN RETURN x END Conj; PROCEDUREIsZero (x: T; ): BOOLEAN = BEGIN RETURN x = Zero; END IsZero; PROCEDUREMul (x, y: T; ): T = BEGIN RETURN x * y END Mul; PROCEDURECheckDivisor (x: T; ) RAISES {Arith.Error} = BEGIN IF x = 0 THEN RAISE Arith.Error(NEW(Arith.ErrorDivisionByZero).init()) END; END CheckDivisor; PROCEDUREDiv (x, y: T; ): T RAISES {Arith.Error} = BEGIN CheckDivisor(y); IF x MOD y # 0 THEN RAISE Arith.Error(NEW(Arith.ErrorIndivisible).init()) END; RETURN x DIV y; END Div; PROCEDURERec (x: T; ): T RAISES {Arith.Error} = BEGIN CASE x OF | 0 => RAISE Arith.Error(NEW(Arith.ErrorDivisionByZero).init()); | 1 => RETURN 1; ELSE RAISE Arith.Error(NEW(Arith.ErrorIndivisible).init()); END; END Rec; PROCEDUREMod (x, y: T; ): T RAISES {Arith.Error} = BEGIN CheckDivisor(y); RETURN x MOD y; END Mod; PROCEDUREDivMod (x, y: T; ): QuotRem RAISES {Arith.Error} = BEGIN CheckDivisor(y); RETURN QuotRem{x MOD y, x DIV y}; END DivMod;
PROCEDUREGCD (x, y: T; ): T = VAR xt, yt: [0 .. BITSIZE(T)] := 0; z : T := One; BEGIN IF x = 0 THEN RETURN y; END; IF y = 0 THEN RETURN x; END; (* This will be optimized to bit shift operations I hope*) (* count the factor 2*) WHILE x MOD 2 = 0 DO x := x DIV 2; INC(xt); END; WHILE y MOD 2 = 0 DO y := y DIV 2; INC(yt); END; WHILE x # y DO IF x <= y THEN z := y - x; ELSE z := x - y; x := y; END; (* both x and y are odd, thus there difference is even*) WHILE z MOD 2 = 0 DO z := z DIV 2; END; y := z; END; RETURN W.LeftShift(x, MIN(xt, yt)); END GCD; BEGIN END IntegerBasic.