No language in title because this is more about the algorithms and not about any particular language. I will however use Python in the code examples.
I've noticed recently that everybody seems to use the same basic algorithm for computing Fibonacci numbers. This kinda bothers me because there are a few faster algorithms that aren't very complex but for some reason nobody seems to know about them.
Fibonacci numbers are often used to teach beginner programmers about recursion and caching or "memoization". The most basic recursive algorithm is something like this:
def fib(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fib(n - 1) + fib(n - 2)
This solution is a pretty straightforward translation from the mathematical definition of the Fibonacci sequence. The problem with it is that it is extremely slow because every step recalculates the intermediate values many times. An easy way to make it faster is to use a cache so the function remembers values it has already calculated. In Python this is pretty simple:
from functools import cache
@cache
def fib(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fib(n - 1) + fib(n - 2)
An iterative solution can save some memory space by avoiding the need for a cache, and it can also avoid extra function calls, thus being a bit faster:
def fib(n):
a, b = 0, 1
while n > 0:
a, b = b, a+b
n -= 1
return a
And this is usually where people usually stop. This is where I would have stopped before about a week ago, when I tried writing this in C using the GNU Multiple Precision arithmetic library (a.k.a. GMP). I was surprised when my basic translation of the iterative version into C was actually a bit slower than the Python version! I decided to read the manual a bit to see if I was doing something wrong when I found GMP's Fibonacci functions. Those ended up being much faster than my simple iterative Python solution. GMP explains the algorithm they use in this manual page. I tried implementing a similar algorithm in Python using some of the identities on the manual page and got a pretty fast Python function (though not as fast as GMP, still much faster than the other Python versions).
from functools import cache
SMALL_FIBS = [
0, 1, 1, 2
3, 5, 8, 13,
21, 34, 55, 89,
144, 233, 377, 610
]
SMALL_FIBS_LEN = len(SMALL_FIBS)
@cache
def fib(n):
if n < SMALL_FIBS_LEN:
return SMALL_FIBS[n]
k = n//2
fib_k = fib(k)
fib_k1 = fib(k - 1)
if n&1: # n is odd
return (2 * fib_k + fib_k1) * (2 * fib_k - fib_k1) + 2*(-1)**k
else:
return fib_k * (fib_k + 2 * fib_k1)
What I don't get is why this version or something similar isn't more well known? It seems similar to exponentiation by squaring, which is a pretty well known way to quickly calculate powers of numbers. Anyway, I just wanted to share this somewhere other than Reddit lol.