0

For finding fibonanci series , i write this code:

def fib(n):
    if n ==1 or n ==0:
        return 1
    else:
        return fib(n-1) + fib(n-2)

this is absolutely ok. But my question is if i call fib() by fib(5) then how many times does it compute the value fib(2) ? And how ?

sorry for the silly question, i am newer in programming

Tanzir Uddin
  • 51
  • 1
  • 9

6 Answers6

1

As polku mentioned in the comments, it's simple enough to see how many times your function is being called:

def fib(n):
    print('Called fib({})'.format(n))
    if n ==1 or n ==0:
        return 1
    else:
        return fib(n-1) + fib(n-2)

>>> fib(5)
Called fib(5)
Called fib(4)
Called fib(3)
Called fib(2)
Called fib(1)
Called fib(0)
Called fib(1)
Called fib(2)
Called fib(1)
Called fib(0)
Called fib(3)
Called fib(2)
Called fib(1)
Called fib(0)
Called fib(1)
8

Your function knows nothing of any of its previous runs, so each time you ask it for a particular value (other than 0 or 1), it has to calculate it all over again. If you want to avoid that, you can use a process called memoization. An easy way to do that in Python is to exploit a common newbie gotcha, the mutable default argument:

def fib2(n, memo=[1, 1]):
    print('Called fib2({})'.format(n))
    if len(memo) > n:
        print('   I already know this one!')
        return memo[n]
    else:
        memo.append(fib2(n-1) + fib2(n-2))
        return memo[-1]

>>> fib2(5)
Called fib2(5)
Called fib2(4)
Called fib2(3)
Called fib2(2)
Called fib2(1)
   I already know this one!
Called fib2(0)
   I already know this one!
Called fib2(1)
   I already know this one!
Called fib2(2)
   I already know this one!
Called fib2(3)
   I already know this one!
8

Each call of the function uses the same memo list object, so appending to it in one call will carry over to future calls.

Community
  • 1
  • 1
glibdud
  • 7,550
  • 4
  • 27
  • 37
1

you can use mutable types like lists and dicts

dict_counts = {}
def fib(n,d):
    v = d.get(n,0)
    d[n]=v+1
    if n ==1 or n ==0:
       return 1
    else:
       return fib(n-1,d) + fib(n-2,d)
fib(5, dict_counts)
print "all counts: ", dict_counts
print "count of f(2) = ", dict_counts.get(2, 0)

output:

all counts: {0: 3, 1: 5, 2: 3, 3: 2, 4: 1, 5: 1}
count of f(2) = 3

dict is a mutable object so you can change values of dict inside the function and access the changes outside the function.

anjaneyulubatta505
  • 10,713
  • 1
  • 52
  • 62
0

If I call fib(5) then how many times does it compute the value fib(2)?

Three. You can see for yourself if you add a print statement.

def fib(n):
    if n == 1 or n == 0:
        return 1
    else:
        print('Computing fib(%i)...' % n)
        return fib(n-1) + fib(n-2)

The output will look like this:

In [4]: fib(5)
Computing fib(5)...
Computing fib(4)...
Computing fib(3)...
Computing fib(2)...
Computing fib(2)...
Computing fib(3)...
Computing fib(2)...
Out[4]: 8

This also gives you some idea of the internal structure of the recursion.

To figure out fib(5), it has to return fib(n-1) + fib(n-2), which is fib(4) - fib(3). It has to compute fib(4) first.

To figure out fib(4), it needs fib(3) and fib(2). It does fib(3) first.

To figure out fib(3), it does fib(2) and fib(1). It does fib(2) first.

To figure out fib(2), it needs fib(1) and fib(0). It does fib(1) first.

Finally, we return without another function call! fib(1) gives us an integer 1 and we can get back to adding to fib(0), which also immediately returns 1.

That addition completes the return of fib(2). Remember this call was part of figuring out fib(3), so now we need the last half of that addition. It is fib(1) so we return immediately and complete the call.

Then we can figure out the last half of fib(3), which means we compute fib(2) again. Both parts of this immediately return and we get the answer.

Now we're back out in fib(4). The first part of it has returned so we need to compute the next half, which is fib(3). This is computed exactly as before.

Hopefully now the stack of Computing fib(n)... makes a bit more sense. :)

Two-Bit Alchemist
  • 17,966
  • 6
  • 47
  • 82
0

fib(2) is calculated 3 times:

>>> fib(5)
computing fib(5)
computing fib(4)
computing fib(3)
computing fib(2)
computing fib(2)
computing fib(3)
computing fib(2)
8

To avoid this duplicate work, you can take an iterative approach to computing the nth Fibonacci number or implement memoization along with your recursion.

Daniel
  • 2,345
  • 4
  • 19
  • 36
0

it is more than once to compute each number and python is very week on recursion.
if you pass 5 to recursion code you have, it would calculate 5 times fib(1), 3 times fib(2), 2 times fib(3), and 1 time fib(4)/fib(5)

faster way to find fib

def fib(n):
...     a, b = 0, 1
...     for _ in xrange(n):
...         a, b = b, a+b
...     return a
galaxyan
  • 5,944
  • 2
  • 19
  • 43
0

Another way to avoid recalculation is to use dynamic programming. You can save the amounts you calculate once in a list, and every time you want to calculate something, look for it in the list first. If you have it there you won't call the function again. You can also put a counter when accessing that list to find out how many times it accesses that. Drawing the execution tree can also help:

for a number n steps will be:

  1. (n-1, n-2)

  2. (n-2, n-3), (n-3, n-4)

  3. (n-3, n-4), (n-4, n-5), (n-4, n-5), (n-5, n-6)

and so on.

Nikign
  • 379
  • 3
  • 9