我最近也在考虑寻找毕达哥拉斯三元组的 Prolog 解决方案。我想出了一个稍微不同的代码。假设我们有一个函数:
isqrt(a) = floor(sqrt(a))
然后枚举 x 和 y 并检查 x*x+y*y 是否是某个 z 的平方就足够了。即检查:
h = x*x+y*y, z = isqrt(h), z*z = h ?
函数 iqrt 可以通过二分法实现。对于对称性破坏,我们可以在 x 之后枚举 y。假设 N = 99,结果代码为:
% between(+Integer, +Integer, -Integer)
between(Lo, Hi, _) :-
Lo > Hi, !, fail.
between(Lo, _, Lo).
between(Lo, Hi, X) :-
Lo2 is Lo+1, between(Lo2, Hi, X).
% bisect(+Integer, +Integer, +Integer, -Integer)
bisect(Lo, Hi, X, Y) :-
Lo+1 < Hi, !,
M is (Lo+Hi) // 2,
S is M*M,
(S > X -> bisect(Lo, M, X, Y);
S < X -> bisect(M, Hi, X, Y);
M = Y).
bisect(Lo, _, _, Lo).
% pythago(-List)
pythago(X) :-
X = [A,B,C],
between(1, 99, A),
between(A, 99, B),
H is A*A+B*B,
bisect(0, H, H, C),
C =< 99, H =:= C*C.
应该有 50 个这样的毕达哥拉斯三元组,另见Sloan 的 A046083:
?- findall(-, pythago(_), L), length(L, N).
N = 52.
人们可能想与以下 CLP(FD) 解决方案进行交叉检查。
:- use_module(library(clpfd)).
% pythago3(-List)
pythago3(X) :-
X = [A,B,C],
X ins 1..99,
A*A+B*B #= C*C,
A #=< B,
label(X).
它提供了相同数量的解决方案:
?- findall(-, pythago3(_), L), length(L, N).
N = 50.