Following from Pillsy's reference to matrix exponentiation, such that for the matrix
M = [1 1]
[1 0]
then
fib(n) = M
n1,2
Raising matrices to powers using repeated multiplication is not very efficient.
Two approaches to matrix exponentiation are divide and conquer which yields Mn in O(ln n) steps, or eigenvalue decomposition which is constant time, but may introduce errors due to limited floating point precision.
If you want an exact value greater than the precision of your floating point implementation, you have to use the O ( ln n ) approach based on this relation:
M
n = (
Mn/2)
2 if
n even
=
M·
Mn-1 if
n is odd
The eigenvalue decomposition on M finds two matrices U and Λ such that Λ is diagonal and
M = U Λ U
-1
Mn = (
U Λ U-1)
n
=
U Λ U-1 U Λ U-1 U Λ U-1 ... n times
=
U Λ Λ Λ ...
U-1
=
U Λ n U-1
Raising a the diagonal matrix
Λ to the
nth power is a simple matter of raising each element in
Λ to the
nth, so this gives an O(1) method of raising
M to the
nth power. However, the values in
Λ are not likely to be integers, so some error will occur.
Defining Λ for our 2x2 matrix as
Λ = [ λ
1 0 ]
= [ 0 λ
2 ]
To find each λ, we solve
|M - λI| = 0
which gives
|M - λI| = -λ ( 1 - λ ) - 1
λ² - λ - 1 = 0
using the quadratic formula
λ = ( -b ± √ ( b² - 4ac ) ) / 2a
= ( 1 ± √5 ) / 2
{ λ
1, λ
2 } = { Φ, 1-Φ } where Φ = ( 1 + √5 ) / 2
If you've read Jason's answer, you can see where this is going to go.
Solving for the eigenvectors X1 and X2:
if X
1 = [
X1,1,
X1,2 ]
M.
X1 1 = λ
1X1
X1,1 +
X1,2 = λ
1 X1,1
X1,1 = λ
1 X1,2
=>
X1 = [ Φ, 1 ]
X2 = [ 1-Φ, 1 ]
These vectors give U:
U = [ X
1,1,
X2,2 ]
[
X1,1,
X2,2 ]
= [ Φ, 1-Φ ]
[ 1, 1 ]
Inverting U using
A = [ a b ]
[ c d ]
=>
A
-1 = ( 1 / |
A| ) [ d -b ]
[ -c a ]
so U-1 is given by
U
-1 = ( 1 / ( Φ - ( 1 - Φ ) ) [ 1 Φ-1 ]
[ -1 Φ ]
U-1 = ( √5 )
-1 [ 1 Φ-1 ]
[ -1 Φ ]
Sanity check:
UΛU
-1 = ( √5 )
-1 [ Φ 1-Φ ] . [ Φ 0 ] . [ 1 Φ-1 ]
[ 1 1 ] [ 0 1-Φ ] [ -1 Φ ]
let Ψ = 1-Φ, the other eigenvalue
as Φ is a root of λ²-λ-1=0
so -ΨΦ = Φ²-Φ = 1
and Ψ+Φ = 1
UΛU-1 = ( √5 )
-1 [ Φ Ψ ] . [ Φ 0 ] . [ 1 -Ψ ]
[ 1 1 ] [ 0 Ψ ] [ -1 Φ ]
= ( √5 )
-1 [ Φ Ψ ] . [ Φ -ΨΦ ]
[ 1 1 ] [ -Ψ ΨΦ ]
= ( √5 )
-1 [ Φ Ψ ] . [ Φ 1 ]
[ 1 1 ] [ -Ψ -1 ]
= ( √5 )
-1 [ Φ²-Ψ² Φ-Ψ ]
[ Φ-Ψ 0 ]
= [ Φ+Ψ 1 ]
[ 1 0 ]
= [ 1 1 ]
[ 1 0 ]
=
M
So the sanity check holds.
Now we have everything we need to calculate Mn1,2:
M
n =
UΛnU-1
= ( √5 )
-1 [ Φ Ψ ] . [ Φ
n 0 ] . [ 1 -Ψ ]
[ 1 1 ] [ 0 Ψ
n ] [ -1 Φ ]
= ( √5 )
-1 [ Φ Ψ ] . [ Φ
n -ΨΦ
n ]
[ 1 1 ] [ -Ψ
n Ψ
nΦ ]
= ( √5 )
-1 [ Φ Ψ ] . [ Φ
n Φ
n-1 ]
[ 1 1 ] [ -Ψ
n -Ψ
n-1 ] as ΨΦ = -1
= ( √5 )
-1 [ Φ
n+1-Ψ
n+1 Φ
n-Ψ
n ]
[ Φ
n-Ψ
n Φ
n-1-Ψ
n-1 ]
so
fib(n) = M
n1,2
= ( Φ
n - (1-Φ)
n ) / √5
Which agrees with the formula given elsewhere.
You can derive it from a recurrance relation, but in engineering computing and simulation calculating the eigenvalues and eigenvectors of large matrices is an important activity, as it gives stability and harmonics of systems of equations, as well as allowing raising matrices to high powers efficiently.