0

Here is my predicate, which should check if the Nth number of Fibonacci is NthFib or not.

I am getting arithmetic is not function error.

K - current iteration
N - Nth number
Tmp - previous Fibonacci number
Ans - current Fibonacci number

Fibonacci sequence: 1, 1, 2, 3, 5, 8, 13, 21, etc. (sum of two previous = current)

fib(N, NthFib) :-
    fib(1, N, 1, 0, NthFib).

fib(K, N, Ans, Tmp, NthFib) :-
    % true if Ans is NthFib, false otherwise
    ( K > N -> Ans is NthFib
    ; K =< N -> fib( K + 1, N, Ans + Tmp, Ans, NthFib)
    ).
false
  • 10,264
  • 13
  • 101
  • 209
Jake Badlands
  • 1,016
  • 3
  • 23
  • 46

3 Answers3

2

First, re-write your original code as

fib(N, NthFib) :- fib(1, N, 1, 0, NthFib).

fib(K, N, Ans, Tmp, NthFib) :- 
  K > N -> Ans = NthFib;       % use = instead of is here
  K =< N -> fib((K+1), N, (Ans+Tmp), Ans, NthFib).

Now,

?- fib(7,X).

X = 1+0+1+ (1+0)+ (1+0+1)+ (1+0+1+ (1+0))+ (1+0+1+ (1+0)+ (1+0+1))+ 
       (1+0+1+ (1+0)+ (1+0+1)+ (1+0+1+ (1+0))) 

Yes
?- fib(7,X), Z is X.

X = 1+0+1+ (1+0)+ (1+0+1)+ (1+0+1+ (1+0))+ (1+0+1+ (1+0)+ (1+0+1))+ 
       (1+0+1+ (1+0)+ (1+0+1)+ (1+0+1+ (1+0)))
Z = 21 

See, in Prolog data is symbolic, and using is forces the arithmetic expression into an arithmetic value (evaluates the expression under assumption that it is a meaningful arithmetic expression).

To check whether 20 is 7-th Fibonacci number, we can use arithmetic comparison operator which evaluates its arguments,

?- fib(7,X), X =:= 20.

No

Which means that your code just needs to be rewritten as

fib(N, NthFib) :- fib(1, N, 1, 0, NthFib).

fib(K, N, Ans, Tmp, NthFib) :- 
  K > N -> NthFib is Ans ;       % exchange the order of operands
  K =< N -> fib((K+1), N, (Ans+Tmp), Ans, NthFib).

Now it works as you intended:

?- fib(7,21).

Yes
?- fib(7,20).

No

But it doesn't work efficiently, carrying all those long expressions around as symbolic data. We only need the numbers really, so just as you were shown in other answers, is is used to achieve that. Every symbolic sub-expression that you have, take it out of its enclosing expression, and name it, using is instead of =.

BTW 21 really is an 8-th member of the sequence. Correct your code.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
1

If K is unified with 1, K + 1 is unified with 1 + 1, not 2.

m09
  • 7,490
  • 3
  • 31
  • 58
joel76
  • 5,565
  • 1
  • 18
  • 22
-1

I have rewrote an algorithm, it is more simple and efficient now:

fib(0, 0).
fib(1, 1).
fib(N, F) :-
    N > 0,
    X is N - 2,
    Y is N - 1,
    fib(X, A),
    fib(Y, B),
    F is A + B.
m09
  • 7,490
  • 3
  • 31
  • 58
Jake Badlands
  • 1,016
  • 3
  • 23
  • 46
  • 2
    No, no, NO! "More efficient"? No, *your original code* was efficient - i.e. linear - this is the classic tree-recursive code which takes enormous amounts of time to calculate the n-th number, as it recalculates fib(X) as part of calculating fib(Y) - whereas your original code ***re-used*** it by explicitly maintaining the two last values. – Will Ness May 25 '12 at 07:25
  • 2
    Yup, it's an exponential complexity algorithm. Your computer won't return much things when `N` is greater than 30 or so. Your previous algorithm - even if poorly implemented - was much better. See Will Ness's answer (+1)! – m09 May 25 '12 at 09:14