是的,可以通过限制值来完成。您还可以将递归移动为尾部递归,但这不是解决方案所必需的:
fibluc(0, 0, 2).
fibluc(1, 1, 1).
fibluc(N, F, L) :-
N in 2..1000,
[F, L] ins 1..sup,
N rem 2 #= 1,
M #= N-1,
F #= (F1 + L1) // 2,
L #= (5*F1 + L1) // 2,
fibluc(M, F1, L1).
fibluc(N, F, L) :-
N in 2..1000,
[F, L] ins 1..sup,
N rem 2 #= 0,
M #= N // 2,
F #= F1 * L1,
L #= (5*F1*F1 + L1*L1) // 2,
fibluc(M, F1, L1).
将产生:
?- fibluc(10, X, Y).
X = 55,
Y = 123 ;
false.
?- fibluc(N, 55, Y).
N = 10,
Y = 123 ;
false.
?- fibluc(N, X, 123).
N = 10,
X = 55 ;
false.
?- fibluc(N, 55, 123).
N = 10 ;
false.
?- fibluc(N, 55, 125).
false.
?- fibluc(N, X, Y).
N = X, X = 0,
Y = 2 ;
N = X, X = Y, Y = 1 ;
N = 3,
X = 2,
Y = 4 ;
N = 7,
X = 13,
Y = 29 ;
N = 15,
X = 610,
Y = 1364 ;
N = 31,
X = 1346269,
Y = 3010349 ;
N = 63,
X = 6557470319842,
Y = 14662949395604 ;
...
这可以被修改以生成对于未实例化的
N
增加值的结果。这里有一个在 Linux 下使用 SWI Prolog 7.1.33 运行的计时、复合查询示例:
?- time((fibluc(100, X, Y), fibluc(N, X, Z))).
X = 354224848179261915075,
Y = Z, Z = 792070839848372253127,
N = 100 ;
false.
?-
使用SWI Prolog 7.2.3版本和相同的代码以及复合查询时,代码需要运行非常长的时间。我等待了至少15分钟仍未终止,现在它还在运行中...我可能会在明天检查一下:)。然而,我已经重新排列了以上代码,将递归调用移回到原始代码所在的位置,如下所示:
fibluc(0, 0, 2).
fibluc(1, 1, 1).
fibluc(N, F, L) :-
N in 2..1000,
[F, L] ins 1..sup,
N rem 2 #= 1,
M #= N-1,
fibluc(M, F1, L1),
F #= (F1 + L1) // 2,
L #= (5*F1 + L1) // 2.
fibluc(N, F, L) :-
N in 2..1000,
[F, L] ins 1..sup,
N rem 2 #= 0,
M #= N // 2,
fibluc(M, F1, L1),
F #= F1 * L1,
L #= (5*F1*F1 + L1*L1) // 2.
在这种情况下,返回了良好的结果。
?- time((fibluc(100, X, Y), fibluc(N, X, Z))).
X = 354224848179261915075,
Y = Z, Z = 792070839848372253127,
N = 100 ;
false.
请注意,CLP(FD)的性能在不同的Prolog解释器之间可能会有很大的差异。有趣的是,在SWI Prolog中,处理尾递归案例的能力在7.1.33版本时暂时存在。