Prolog; try to make fibonacci more effective?

烂漫一生 提交于 2019-12-04 02:41:51

I could post here the solution, but since that this is homework, it would be counter-productive. Instead, here's a lead:

The problem with the version of Fibonacci that you listed is that it is inefficient. Each call to fibo/2 causes another two calls, but some of these calls calculate the values of the same Fibonacci numbers. For example, in pseudo-code:

(a) fibo(4) -> fibo(3), fibo(2)
(b) fibo(3) -> fibo(2), fibo(1)
(c) fibo(2) -> fibo(1), fibo(0) % called from (a)
(d) fibo(2) -> fibo(1), fibo(0) % called from (b), redundant

To overcome this deficiency, you were asked to rephrase Fibonacci in terms of returning not just the last value, but the last two values, so that each call to fib/3 will cause only a single recursive call (hence calculate the Fibonacci series in linear time). You'll need to change the base cases to:

fib(1,1,0).
fib(2,1,1).

I'll leave the recursive case to you.


For the impatient

Here is the recursive case as well:

fib(N, Val, Last) :-
  N > 2,
  N1 is N - 1,
  fib(N1, Last, Last1), % single call with two output arguments, 
                        % instead of two calls with one output argument
  Val is Last + Last1.
mat

See the related discussion:

Generalizing Fibonacci sequence with SICStus Prolog

and consider ony's very good solution using finite domain constraints from there.

Perhaps using tail recursion is a good option

edit: Instead of breaking fib(6) into fib(5)+fib(4) you might try something like fib(6) = fib(6,0,0) the first parameter is the count of steps, when it reaches 0 you stop, the second parameter the last value you calculated, and the third parameter is the value to calculate which is equal to the sum of current second and third parameters (with the exception of the first step, in which 0 + 0 will be 1)

So to calculate you set the second parameter at each call and acumulate in the third so fib(6,0,0) => fib(5,0,1) => fib(4,1,1) => fib(3,1,2) => fib(2,2,3) => fib(1,3,5) => fib(0,5,8) then you return 8

In that method you dont actually have to save in the stack the adress return, avoiding stack overflow

Remember that there is another way to calculate the Fibonacci sequence: starting from the base case and moving up.

Right now, to calculate fib(n), you add fib(n-1) and fib(n-2). Instead, flip that around and calculate fib(0) and fib(1) based on the definition of the Fibonacci sequence, and build up from that.

You almost already have it. Just rewrite:

fibo(N, Value) :-
N1 is N-1, N2 is N-2,
 fibo(N1, LastValue),fibo(N2, SecondToLastValue),
 Value is LastValue + SecondToLastValue.

in terms of

fibo2(N, Value, LastValue):- ...

I don't understand how I can rewrite this using accumulation

Just don't, this is not needed (although it's possible to do so).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!