2

Could anyone explain why this line fibValue[n] = result makes everything so much faster? Just taking out that line it takes ages for anything over 30 to load. Thanks in advance!

fibValue = { 0: 0, 1: 1}

def fib(n):
    if n in fibValue.keys():
        return fibValue[n]
    else:
        result = fib(n-1) + fib(n-2)
        fibValue[n] = result
        return result

result = fib(int(input("Enter number: ")))
print(result)
TrebledJ
  • 7,857
  • 7
  • 22
  • 46
Flapjack
  • 65
  • 6
  • 1
    draw a stack tree for both the versions and find out – guttume Dec 19 '18 at 13:49
  • 2
    Well what do you think that line does? – EdChum Dec 19 '18 at 13:49
  • You are _caching_ earlier results. You trade memory against run-time , often made choice ... btw. you store too much , you only need 2 numbers to store for your little program – Patrick Artner Dec 19 '18 at 13:50
  • I got no clue what that line does,I tried taking it out while practicing, cause I thought it wasnt doing much but it just made everything slower. – Flapjack Dec 19 '18 at 13:51
  • You will find the explanation here https://www.youtube.com/watch?v=vJ2fu-pnFTw – guttume Dec 19 '18 at 13:51
  • See [fiboinaci generator](https://stackoverflow.com/a/24846766/7505395) answer for even faster one - it only stores 2 numbers and does not need the overhead of a dictionary – Patrick Artner Dec 19 '18 at 13:54
  • @guttume Ty, will check it out. :D – Flapjack Dec 19 '18 at 14:01
  • 1
    Note that the `if n in fibValue.keys():` test is quite inefficient (it builds a sequence of keys and do a sequential lookup - which is 0(n)) - you should use `if n in fibValues:` instead (which uses the hash of n to do a 0(1) lookup). – bruno desthuilliers Dec 19 '18 at 14:11

2 Answers2

4

That right there is a technique called dynamic programming (aka. memoisation), whereby you store and reuse computed results. This makes lookup and computation much, much faster later on.

When you remove fibValue[n] = result, you don't store the result, and by not storing the result, you need to recompute the fibonacci for that particular number n.

Consider computing fib(6). On the first function call, you get

fib(6) = fib(5) + fib(4)

By recursion, this gives

fib(6) =                       fib(4)               +            fib(3)        +             fib(3)       +     fib(2)

fib(6) =            fib(3)        +     fib(2)      +     fib(2)      + fib(1) +      fib(2)     + fib(1) + fib(1) + fib(0)

fib(6) =      fib(2)     + fib(1) + fib(1) + fib(0) + fib(1) + fib(0) + fib(1) + fib(1) + fib(0) + fib(1) + fib(1) + fib(0)

fib(6) = fib(1) + fib(0) + fib(1) + fib(1) + fib(0) + fib(1) + fib(0) + fib(1) + fib(1) + fib(0) + fib(1) + fib(1) + fib(0)

fib(6) =    1   +    1   +    1   +    1   +    1   +    1   +    1   +    1   +   1   +    1   +    1   +    1   +    1

fib(6) =    13

You could see that fib(3) and fib(2) were computed at least 3 times each. Now consider if your input is much bigger (say 1000). You'd be computing fib(3), fib(100), fib(200), etc. repeatedly. This wastes a huge amount of time. Thus, to save time (since we're programmers, we're very woo about time), we trade in space (i.e. memory) to cache previous computations and thus... save time by doing lookup on the cache.

The time complexity of performing lookup on a Python dictionary is (on average) O(1), this takes constant time, and is the best thing a programmer might wish for in an algorithm. Compare that to the unwieldy time complexity of computing a fib(n) from scratch. (Note that, as @brunodesthuilliers commented, your function currently performs lookup by iterating through a dict.keys() object, which will result in a (worse-case) O(n) time-complexity for lookup. Simply changing if n in fibValue.keys() to if n in fibValue may result in faster computation.)

As suggested by @PatrickArtner, if you're only finding a single fibonacci value, you could make your fibonacci calculator more efficient time-and-space-wise by only storing two values (i.e. the most recent fib values) instead of caching every result.

TrebledJ
  • 7,857
  • 7
  • 22
  • 46
0

The technique that you used here to compute fibonacci series is called Dynamic Programming method.

Dynamic Programming method divides the problems into the sub problems and solves each sub problem and saves the result of each sub problem.

These results are used to solve other sub problems. So it makes the algorithm faster.

Hemang Vyas
  • 179
  • 1
  • 10