Fibonacci数的序列 - Prolog

时间:2013-10-25 00:30:40

标签: prolog range fibonacci

在尝试学习Prolog时,我遇到了一个很好的练习,那就是编写一个显示Nth Fibonacci数的程序。经过一些工作后,我开始工作,然后决定是否可以编写一个程序,根据输入显示一系列Fibonacci数字。

例如输入:

?- fib_sequence(2,5,Output).

给出输出:

?- Output = [1,1,2,3]
然而,我很难找到一个好的起点。这就是我到目前为止所做的:

fib(0, 0).
fib(1, 1).
fib(N, F) :- X is N - 1, Y is N - 2, fib(X, A), fib(Y, B), F is A + B.

fib_sequence(A,B,R) :- fib(A,Y) , fib(B,Z).

我知道我必须为 R 分配一个值,但我不确定如何分配多个值。非常感谢任何帮助。

3 个答案:

答案 0 :(得分:3)

观察您的fib_sequence无法在单个谓词子句中完成:您需要至少两个来保持递归 - 一个在A大于B时生成一个空列表(即我们已经耗尽了从A到B的范围),另一个将Xfib(A,X)添加到您正在构建的列表中,通过A增加1 ,并递归调用fib_sequence以生成序列的其余部分。

第一个谓词子句如下所示:

fib_sequence(A,B,[]) :- A > B.

第二个谓词条款有点难:

fib_sequence(A,B,[H|T]) :-
    A =< B                   /* Make sure A is less than or equal to B */
,   fib(A, H)                /* Produce the head value from fib(A,...) */
,   AA is A + 1              /* Produce A+1 */
,   fib_sequence(AA, B, T).  /* Produce the rest of the list */

答案 1 :(得分:1)

Prolog有一些内置的帮助器来处理数字序列,然后作为dasblinkenlight回答的替代方法,这里是一个惯用的'查询':

fib_sequence(First, Last, Seq) :-
    findall(F, (between(First,Last,N), fib(N,F)), Seq).

请注意,它不会与你的fib / 2开箱即用,因为有一个错误:我添加了一个条件,避免你尝试回溯的无限循环 on fib / 2解决方案:

fib(N, F) :- N > 1, % added sanity check
    X is N - 1, Y is N - 2, fib(X, A), fib(Y, B), F is A + B.

答案 2 :(得分:1)

这是另一种方法。首先,我稍微重新设置fib,以便它只递归调用一次而不是两次。为此,我创建了一个谓词,它返回前两个Fibonacci值而不是最后一个:

fib(N, F) :-
    fib(N, F, _).
fib(N, F, F1) :-
    N > 2,
    N1 is N-1,
    fib(N1, F1, F0),
    F is F0 + F1.
fib(1, 1, 0).
fib(2, 1, 1).

为了获得序列,我选择了一个内置Fibonacci计算的算法,这样就不需要调用fib O(n ^ 2)次。但是,它确实需要在完成后反转列表:

fib_sequence(A, B, FS) :-
    fib_seq_(A, B, FSR),
    reverse(FSR, FS).

fib_sequence_(A, B, []) :-
    A > B.
fib_sequence_(A, B, [F]) :-
    A =:= B,
    fib(A, F, _).
fib_sequence_(A, B, [F1,F0]) :-
    1 is B - A,
    fib(B, F1, F0).
fib_sequence_(A, B, [F2,F1,F0|FT] ) :-
    B > A,
    B1 is B - 1,
    fib_sequence_(A, B1, [F1,F0|FT]),
    F2 is F1 + F0.

这是另一种方法,没有相反的方法,但上面的反向方法似乎仍然执行得快一点。

fib_sequence_dl(A, B, F) :-
    fib_sequence_dl_(A, B, F, [_,_|[]]).

fib_sequence_dl_(A, B, [], _) :-
    A > B, !.
fib_sequence_dl_(A, B, [F], _) :-
    A =:= B,
    fib(A, F, _), !.
fib_sequence_dl_(A, B, [F0,F1|T], [F0,F1|T]) :-
    1 is B - A,
    fib(B, F1, F0), !.
fib_sequence_dl_(A, B, F, [F1,F2|T]) :-
    A < B,
    B1 is B - 1,
    fib_sequence_dl_(A, B1, F, [F0,F1|[F2|T]]),
    F2 is F0 + F1.