问题
Rosetta code delivers me the following code snippet for modinv/3. It does calculate extended GCD via egcd/4 and then derives from it modinv/3:
egcd(_, 0, 1, 0) :- !.
egcd(A, B, X, Y) :-
divmod(A, B, Q, R),
egcd(B, R, S, X),
Y is S - Q*X.
modinv(A, B, N) :-
egcd(A, B, X, Y),
A*X + B*Y =:= 1,
N is X mod B.
Example queries:
?- modinv(42, 2017, N).
N = 1969.
?- modinv(42, 64, X).
false.
There is a slight problem with the solution. It is not tail recursive. Namely the (is)/2 is the last call of egcd/4 and not egcd/4 itself.
So the predicate might build-up a stack, a stack that might contain large big numbers. How would one go about and realize a more tail recursive solution?
回答1:
The same site you mention has other algorithms amenable for a tail recursive solution.
Here I translated one from the C++ section (note there is a constraint missing in the original C++ code, it is not checking the last value of A):
modinv(A, B, N):-
modinv(A, B, 1, 0, N1),
(N1 < 0 -> N is N1 + B ; N1 = N).
modinv(A, B, X, Y, N):-
(B=0 -> (A=1, N=X) ;
(
divmod(A, B, Q, R),
Exp is X - Y * Q,
modinv(B, R, Y, Exp, N)
)
).
Sample queries:
?- modinv(42, 2017, N).
N = 1969.
?- modinv(42, 64, X).
false.
来源:https://stackoverflow.com/questions/65242927/truly-tail-recursive-modinverse-in-prolog