
Fibonacci series and Dynamic programming - aditgupta
http://functionspace.org/articles/32/Fibonacci-series-and-Dynamic-programming
======
blt
The fastest way to calculate the Fibonacci sequence (with integer math) is a
simple loop, just like you'd do it on paper. This version is slower _and_ much
more complicated. With so many relevant good examples of recursion and dynamic
programming, it boggles my mind to see the Fibonacci sequence used as an
example for either.

    
    
        def fib(n):
            a, b = 0, 1
            for k in range(n):
                a, b = b, a + b
            return a

~~~
d0mine
Here's O(log n) solution [1]:

    
    
      def fib_sicp(n):
          a, b, p, q = 1, 0, 0, 1
          while n > 0:
              if n % 2 == 0: # even
                  oldp = p
                  p = p*p + q*q
                  q = 2*oldp*q + q*q
                  n //= 2
              else:
                  olda = a
                  a = b*q + a*q + a*p
                  b = b*p + olda*q
                  n -= 1
          return b
      

[1]: [http://stackoverflow.com/questions/1525521/nth-fibonacci-
num...](http://stackoverflow.com/questions/1525521/nth-fibonacci-number-in-
sublinear-time/1526036#1526036)

It is ~20 times faster for n=10000

~~~
blt
Cool - did not know about that. Wish I could edit my comment.

------
crntaylor
I can't resist a quick plug for this beautiful O(n) implementation of the
fibonacci sequence in Haskell. One line to define the list `fibs` -- an
infinite list of fibonacci numbers -- and one line to define the function
`fib` which simply takes the n'th element of the list.

    
    
        λ> let fibs  = 0 : 1 : zipWith (+) fibs (tail fibs)
        λ> let fib n = fibs!!n
        λ> fib 100
        354224848179261915075

~~~
taeric
Correct me if I'm wrong, but this is also O(n) in space, right? I think you
can get a similar scala version in:

    
    
        lazy val fib:Stream[BigInt] = 0 #::1 #:: fib.zip(fib.tail).map(x=>x._1+x._2)
    

This is neat and all, but the imperative version wins by being O(1) in space.
Right?

~~~
tmoertel
No, the Haskell version will operate in constant space provided you don't hold
onto the list:

    
    
        let fibs = 1 : 1 : zipWith (+) fibs (tail fibs) in fibs !! 100
    

Since the fibs list is visible only to the expression (fibs !! 100), and since
the (!!) operator advances through the list discarding elements until it hits
the 100th, those elements are free to be garbage collected. Further, since the
elements of the list (after the first two) are generated only when consumed,
only a few of the cons cells will ever be live at any point in time.

~~~
taeric
That makes sense, and I would think should be true in the Scala version as
well. I did not know if it was, though. I guess I would have to spent a lot
more time digging the details of the environment created to really see where
the head of the list is dropped from scope.

Specifically, I would expect space to grow at O(n), but that it could be
garbage collected quickly. The question is, how quickly would the garbage
collector do its thing. Or are you saying that is dodged in the Haskell
version, as well?

------
tmoertel
Perhaps surprisingly, you can convert many recursive algorithms into
equivalent iterative versions using a series of simple mechanical steps. For
example, if we start with the naive recursive implementation of our beloved
fib function,

    
    
        def fib(n):
            if n < 2:
                return n
            return fib(n - 1) + fib(n - 2)
    

we can arrive at the iterative (dynamic-programming) version that follows,

    
    
        def fib(n):
            fibn1, fibn2 = (0, 1)
            for _ in xrange(n):
                fibn1, fibn2 = fibn2, fibn1 + fibn2
            return fibn1
    

through the following steps:
[https://gist.github.com/tmoertel/5798134](https://gist.github.com/tmoertel/5798134)

If you're interested in this kind of thing, I'm writing a series of articles
on converting recursive algorithms into iterative algorithms. The initial
article: [http://blog.moertel.com/posts/2013-05-11-recursive-to-
iterat...](http://blog.moertel.com/posts/2013-05-11-recursive-to-
iterative.html)

~~~
mechagodzilla
Here is the Fibonacci sequence calculated by a literal series of mechanical
steps: [http://www.chrisfenton.com/the-turbo-
entabulator/](http://www.chrisfenton.com/the-turbo-entabulator/)

------
peter_l_downs
Or you could apply some math and come up with a generating function!

[http://www.math.ufl.edu/~joelar/generatingfibonacci.pdf](http://www.math.ufl.edu/~joelar/generatingfibonacci.pdf)

~~~
antiterra
And, if you want to know more about generating functions, you can check out
the book "generatingfunctionology" by the recently late Herbert Wilf _gratis_
at
[http://www.math.upenn.edu/~wilf/DownldGF.html](http://www.math.upenn.edu/~wilf/DownldGF.html)

~~~
tmoertel
Another great resource on generating functions is _Analytic Combinatorics_ by
Philippe Flajolet and Robert Sedgewick:

[http://algo.inria.fr/flajolet/Publications/book.pdf](http://algo.inria.fr/flajolet/Publications/book.pdf)

------
prakashk
Perl 6 (from [1]):

    
    
        > my @fib := 1, 1, *+* ... *; @fib[99]
        354224848179261915075
    
        > (1, 1, *+* ... *)[99]
        354224848179261915075
    

[1]
[https://justrakudoit.wordpress.com/2010/12/29/perl-6-fibonac...](https://justrakudoit.wordpress.com/2010/12/29/perl-6-fibonacci-
versus-haskell/)

------
pathikrit
A O(n) Scala one:
[https://github.com/pathikrit/scalgos/blob/master/src/main/sc...](https://github.com/pathikrit/scalgos/blob/master/src/main/scala/com/github/pathikrit/scalgos/Combinatorics.scala#L100)

------
jgeerts
Reminds me awefully much about the blog post below.

[http://agillo.net/getting-groovy-with-fibonacci/](http://agillo.net/getting-
groovy-with-fibonacci/)

------
dhruvchandna
In Clojure you can implement this as:

    
    
        (def fib-list (map first (iterate (fn [[a b]] [b (+ a b)]) [0N 1N])))
    
        (nth fib-list 100)
        354224848179261915075N

------
amckinlay
Doesn't Clojure have a .memoize() that would be useful here?

