我正在使用 SWI Prolog 学习 Prolog,我对斐波那契数计算程序的以下两种解决方案有疑问:
第一个是这样的:
fib(1,1).
fib(2,1).
fib(N,F) :- N > 2,
N1 is N-1,
fib(N1,F1),
N2 is N-2,
fib(N2,F2),
F is F1+F2.
对我来说很清楚它的工作原理,它非常简单。
然后我有第二个版本,在阅读代码时,它似乎与前一个版本一样工作,但之后它计算了 N 的斐波那契数,通过asserta/2谓词将其保存在 Prolog 数据库中,以便之后重用。
因此,例如,如果我计算 10 和 11 的斐波那契数,当我计算 12 的斐波那契数时,我将考虑使用前 2 次计算的结果。
所以我的代码是:
:-dynamic fibDyn/2.
fibDyn(1,1).
fibDyn(2,1).
fibDyn(N,F) :- N > 2,
N1 is N-1,
fibDyn(N1,F1),
N2 is N-2,
fibDyn(N2,F2),
F is F1+F2,
asserta(fibDyn(N,F)).
在我看来,逻辑与前一个相同:
如果 N>2,F 是 N 的斐波那契数,并使用递归来计算 N 的斐波那契数(如前面的示例中所示)
如果我要求计算我已经计算的数字的斐波那契数的数量并将其放入其前身(或其中一些)的斐波那契数的数据库中,我希望该程序更快,但在我看来它可以工作一种奇怪的方式:它太快了,并且能够直接计算非常大的整数的斐波那契数(其他版本在这么大的数字上出错)
另一个奇怪的事情是,如果我对查询进行跟踪,我会得到如下信息:
[trace] ?- fibDyn(200,Fib).
Call: (6) fibDyn(200, _G1158) ? creep
Exit: (6) fibDyn(200, 280571172992510140037611932413038677189525) ? creep
Fib = 280571172992510140037611932413038677189525 .
如您所见,似乎不执行斐波那契谓词的代码,而是直接获取结果(从哪里?!?!)
如果我执行这个查询(使用第一个版本),我会得到程序将计算它:
[trace] ?- fib(3,Fib).
Call: (6) fib(3, _G1158) ? creep
^ Call: (7) 3>2 ? creep
^ Exit: (7) 3>2 ? creep
^ Call: (7) _G1233 is 3+ -1 ? creep
^ Exit: (7) 2 is 3+ -1 ? creep
Call: (7) fib(2, _G1231) ? creep
Exit: (7) fib(2, 1) ? creep
^ Call: (7) _G1236 is 3+ -2 ? creep
^ Exit: (7) 1 is 3+ -2 ? creep
Call: (7) fib(1, _G1234) ? creep
Exit: (7) fib(1, 1) ? creep
^ Call: (7) _G1158 is 1+1 ? creep
^ Exit: (7) 2 is 1+1 ? creep
Exit: (6) fib(3, 2) ? creep
Fib = 2 .
为什么?我希望第二个版本(使用asserta谓词的版本)将计算两个数字的斐波那契数,并使用这些值生成下一个的解决方案。
例如,我可能有以下情况:我还没有计算任何斐波那契数,我要求计算 N=4 的斐波那契数,所以它计算它(如在第二个发布的堆栈跟踪中)。
所以我要求计算 N=5 的斐波那契数,他使用 N=4 的斐波那契数来保存它。然后我要求它计算 N=6 的斐波那契数,它最终可以使用保存的 4 和 5 的斐波那契数
我错过了什么?你能帮我理解吗?