The integer sequence 0, 1, 1, 2, 3, 5, 8, 13, … is well known as the Fibonacci sequence. It is easily defined by , and for .
To compute you could use this definition directly, but that leads to a highly inefficient algorithm that is both recursive and which uses a number of additions which grows exponentially with .
The first observation that leads to a better algorithm is that we can iteratively compute and at each step, we only need the previous two values from the sequence. So if we set
and then we have , where means that the operator is applied times (and is the identity). This reduces the number of iterations to which is much much better than exponential growth.
But it can get even better. The following method is inspired by Exercise 1.19 in the book Structure and Interpretation of Computer Programs. The key observation is that if we introduce
then we have both and
Why is this important? Because now we have
Notice how this type of reduction rules are very similar to those found in the Evaluation of Powers post. Let us look at an example and try to evaluate using these rules:
Then we just have to extract the second component (as done by applying the function) and we get .
It is clear that the number and type of steps depend on the binary representation of when computing using this method. Actually, reduction rule 2 will be performed times and the number of times reduction rule 3 is performed corresponds to the number of 1s in the binary representation of . So the total number of steps needed for evaluating using this method is logarithmic in .
Let us look at a C++
implementation. A straightforward implementation is this:
fibtype fib_rec(fibtype a, fibtype b, fibtype p, fibtype q, unsigned count) {
if (count == 0)
return b;
if (count % 2 == 0)
return fib_rec(a, b, p*p+q*q, 2*p*q+q*q, count/2);
return fib_rec(b*q+a*q+a*p, b*p+a*q, p, q, count-1);
}
where = fib_rec(1, 0, 0, 1, n)
(fibtype
is just a typedef
for an appropriate integer type.) It can be made iterative and improved at bit in the following way:
fibtype fibonacci(unsigned n) {
if (n <= 1) return n;
fibtype a=1, b=0, p=0, q=1, tmp;
while (n != 1) {
if (n % 2 != 0) {
tmp = b*q + a*q + a*p;
b = b*p + a*q;
a = tmp;
}
tmp = p*p + q*q;
q = (2*p + q)*q;
p = tmp;
n /= 2;
}
return b*p + a*q;
}
The most important improvement here is probably the observation that .
I don't claim that this is the fastest possible method for evaluating (single) Fibonacci numbers, but it certainly beats the "traditional" methods mentioned in the beginning (it may be inferior for small , though). Note also that as long as the numbers fit into the registers of the computer, the time necessary to perform each step is bounded by a constant. If multiple-precision is needed, however, this may no longer the case.
Please inform me of other fast ways to compute Fibonacci numbers.
(Update 2014-03-25: The source for the last algorithm can be found as a snippet)