我试着在Prolog中编写一个代码来寻找GCD(不使用modulo) 谁能告诉我这个程序有什么问题?
gcd(X,Y,Z):- X>=Y, X1=X-Y, gcd(X1,Y,Z).
gcd(X,Y,Z):- X<Y, X1=Y- X, gcd(X1,X,Z).
gcd(0,X,X):- X>0.
答案 0 :(得分:4)
至于为什么原始实现不起作用,有两个原因:
谓词=/2
用于统一,而非算术分配
表达式X1 = X - Y
不会从Y
中减去X
并将结果存储在X1
中。相反,它将X1
与术语-(X,Y)
统一起来。例如,如果X=5
和Y=3
,则结果为X1=5-3
,而不是X1=2
。解决方案是使用is/2
来分配评估的算术表达式:X1 is X - Y
。
除基本案例谓词外,其他谓词成功匹配基本案例
子句gcd(0,X,X) :- X > 0.
是一个合理的基本情况,但它永远不会尝试,因为第二个子句(gcd(X,Y,Z):- X<Y,...
)总是首先成功匹配相同的条件,导致无限递归和堆栈溢出
解决此问题的一种方法是将基本案例移动到第一个子句,并在成功执行后使用剪切以避免回溯:
gcd(0, X, X):- X > 0, !.
gcd(X, Y, Z):- X >= Y, X1 is X-Y, gcd(X1,Y,Z).
gcd(X, Y, Z):- X < Y, X1 is Y-X, gcd(X1,X,Z).
现在可以使用了:
| ?- gcd(10,6,X).
X = 2 ? ;
(1 ms) no
| ?- gcd(10,5,X).
X = 5 ? ;
no
(注意:此处的“否”表示找到第一个后找不到更多解决方案)
<小时/> 的附录强>
上述实施中仍有一些“差距”。一个是它没有优雅地处理gcd(0, 0, R)
(它溢出)。其次,它不处理负值。一种可能的解决方案是详细说明这些情况:
gcd(X, Y, Z) :-
X < 0, !,
gcd(-X, Y, Z).
gcd(X, Y, Z) :-
Y < 0, !,
gcd(X, -Y, Z).
gcd(X, 0, X) :- X > 0.
gcd(0, Y, Y) :- Y > 0.
gcd(X, Y, Z) :-
X > Y, Y > 0,
X1 is X - Y,
gcd(Y, X1, Z).
gcd(X, Y, Z) :-
X =< Y, X > 0,
Y1 is Y - X,
gcd(X, Y1, Z).
答案 1 :(得分:1)
请尝试以下方法:
gcd(X, 0, X):- !.
gcd(0, X, X):- !.
gcd(X, Y, D):- X =< Y, !, Z is Y - X, gcd(X, Z, D).
gcd(X, Y, D):- gcd(Y, X, D).
采用各种语言的GCD rosettacode.org。
答案 2 :(得分:1)
GCD的Prolog代码
gcd(X,Y,G) :- X=Y, G=X.
gcd(X,Y,G) :- X<Y, Y1 is Y-X, gcd(X,Y1,G).
gcd(X,Y,G) :- X>Y ,gcd(Y,X,G).
?- gcd(24,16,G).
G = 8
答案 3 :(得分:0)
prolog答案是: -
gcd(X,0,X).
gcd(X,Y,R):-
Y>0,
X1 is X mod Y,
gcd(Y,X1,R).
答案 4 :(得分:0)
gcd(A,B,X):- B=0,X=A.
gcd(A,B,X):- A>B, gcd(B, A, X).
gcd(A,B,X) :- A<B, T is B mod A, gcd(A, T, X).
答案 5 :(得分:0)
使用欧几里得算法的两个数的GCD的简单易读Prolog代码。
gcd(A,B,X):- A=0,X=B. % base case
gcd(A,B,X):- B=0,X=A. % base case
gcd(A,B,X):- A>B, gcd(B, A, X).
gcd(A,B,X):- A<B, T is B mod A, gcd(A, T, X).
查询如下:
gcd(147,210,GCD).
输出:
GCD = 21
答案 6 :(得分:0)
gc(X,Y,Z):- (
X=0 -> (
Z is Y
);
Y=0 -> (
Z is X
);
X=Y -> (
Z is X
);
X>Y -> (
Y1 is X-Y,
gc(Y1,Y,Z)
);
X<Y->(
Y1 is Y-X,
gc(X,Y1,Z)
)
).