]> Repositorios git - scryer-prolog.git/commitdiff
Implemented expmod/4
authornotoria <[email protected]>
Sat, 2 May 2020 01:36:01 +0000 (03:36 +0200)
committernotoria <[email protected]>
Sat, 2 May 2020 12:56:07 +0000 (14:56 +0200)
src/prolog/lib/arithmetic.pl

index d367d3656af648f7091dec0ee516eb34aa8c4723..f0d2b58ec28fff9bc2e696b4055671a26f06ccaa 100644 (file)
@@ -1,4 +1,4 @@
-:- module(arithmetic, [lsb/2, msb/2, number_to_rational/2,
+:- module(arithmetic, [expmod/4, lsb/2, msb/2, number_to_rational/2,
                        number_to_rational/3,
                        rational_numerator_denominator/3]).
 
@@ -6,6 +6,28 @@
 :- use_module(library(error)).
 :- use_module(library(lists), [append/3, member/2]).
 
+expmod(Base, Expo, Mod, R) :-
+    (   member(N, [Base, Expo, Mod]), var(N) -> instantiation_error(expmod/4)
+    ;   member(N, [Base, Expo, Mod]), \+ integer(N) ->
+        type_error(integer, N, expmod/4)
+    ;   Expo < 0 -> domain_error(not_less_than_zero, Expo, expmod/4)
+    ;   expmod_(Base, Expo, Mod, 1, R)
+    ).
+
+expmod_(_, _, 1, _, 0) :- !.
+expmod_(_, 0, _, R, R) :- !.
+expmod_(Base0, Expo0, Mod, C0, R) :-
+    Expo0 /\ 1 =:= 1,
+    C is (C0 * Base0) mod Mod,
+    !,
+    Expo is Expo0 >> 1,
+    Base is (Base0 * Base0) mod Mod,
+    expmod_(Base, Expo, Mod, C, R).
+expmod_(Base0, Expo0, Mod, C, R) :-
+    Expo is Expo0 >> 1,
+    Base is (Base0 * Base0) mod Mod,
+    expmod_(Base, Expo, Mod, C, R).
+
 lsb(X, N) :-
     builtins:must_be_number(X, lsb/2),
     (   \+ integer(X) -> type_error(integer, X, lsb/2)