Truly Tail-Recursive modInverse() in Prolog

半城伤御伤魂 提交于 2021-01-05 11:50:56

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!