🔒 Locked
Fibonacci Time Efficiency
Advertisement
Original Post
I have a recursive algorithm to generate Fibonacci numbers (for use in a puzzle game), and I would like to increase the efficiency class to O(1), but right now I only have it O(n). Since the input can be quite large, I need to limit computing time to be as efficient as possible. I suppose I could use the iterative definition of the nth Fib number, but I'm not sure how to go about it. Here is my recursive algorithm Fib(n) // n positive integer { if(n<3) return 1; // base Fib number else return F(n-1) + F(n-2); // definiton of the nth fibonacci number } Thanks for the help
If you want to go iterative (ie dynamic programming):
or you could even do it recursively (ie memoization):
Memoization caches your results so that you never end up recomputing the same recursion subtree more than once.
int fib[20];fib[0]=fib[1]=1;for(int c=2;c<20;c++) fib[c]=fib[c-1]+fib[c-2];or you could even do it recursively (ie memoization):
int fib[20];int getfib(int n) { if(n==0||n==1) return 1; if(fib[n]!=-1) return fib[n]; return fib[n]=getfib(n-1)+getfib(n-2);}int main() { memset(fib,-1,sizeof(fib)); cout<<getfib(10);}Memoization caches your results so that you never end up recomputing the same recursion subtree more than once.
Here's the best method I know of. If you have two consecutive Fibonacci numbers F(n) and F(n+1) as a column, you can multiply on the left by the matrix
and you get
The result of this operation is advancing from (F(n),F(n+1)) to (F(n+1),F(n+2)). We can start with (0,1) -which is (F(0),F(1))- and repeat this operation n times. What you get is the following formula:
The n-th power of the matrix can be computed in log(n) matrix multiplications, using a binary exponentiation method. You can also note that all the matrices you need have the following form:
You can see that the multiplication of two such matrices yields another matrix of the same type:
So you can just do all the operations with a type like
This results in an algorithm that requires log(n) multiplications to compute F(n). Of course, instead of doubles, you can do the whole thing using some large integer class and the algorithm would still work.
A similar algorithm can be obtained by implementing a class that represents numbers in the field named Q[sqrt(5)], which consists of numbers that are of the form a+b*sqrt(5), where a and b are rationals.
Here's another method, good enough if you just want your result as doubles:
(0 1)(1 1)and you get
(0 1) ( F(n) ) ( F(n+1) ) (F(n+1))(1 1) * (F(n+1)) = (F(n)+F(n+1)) = (F(n+2))The result of this operation is advancing from (F(n),F(n+1)) to (F(n+1),F(n+2)). We can start with (0,1) -which is (F(0),F(1))- and repeat this operation n times. What you get is the following formula:
(0 1)^n (0) ( F(n) )(1 1) * (1) = (F(n+1))The n-th power of the matrix can be computed in log(n) matrix multiplications, using a binary exponentiation method. You can also note that all the matrices you need have the following form:
(a b )(b a+b)You can see that the multiplication of two such matrices yields another matrix of the same type:
(a b ) (x y ) ( a*x+b*y a*y+b*x+b*y )(b a+b) * (y x+y) = (b*x+a*y+b*y 2*b*y+a*x+a*y+b*x)So you can just do all the operations with a type like
struct FibMatrix { double a,b; FibMatrix(double a,double b):a(a),b(b){} FibMatrix operator * (FibMatrix const &fm){ return FibMatrix(a*fm.a+b*fm.b,a*fm.b+b*(fm.a+fm.b)); }};This results in an algorithm that requires log(n) multiplications to compute F(n). Of course, instead of doubles, you can do the whole thing using some large integer class and the algorithm would still work.
A similar algorithm can be obtained by implementing a class that represents numbers in the field named Q[sqrt(5)], which consists of numbers that are of the form a+b*sqrt(5), where a and b are rationals.
Here's another method, good enough if you just want your result as doubles:
double Fib(int n){ floor(.5+pow((1.0+sqrt(5.0))*.5,n)/sqrt(5.0));}
Of course, to reeeally get O(1) effeciency, you could precompute all of the values of the Fibonacci seqence you need. Not nice to extreme-memory-saving-devices, but for your typical household computer, you'd never know the difference, and it's instant.
Sometimes tradeoffs like this one are the best ;)
Sometimes tradeoffs like this one are the best ;)
here for a O(1) algorithm:
const float sq5 = (float)sqrt(5.0f);
const float gold = (float)(sqrt(1.25f) + 0.5f);
int fibonacci(int n)
{
if (n < 0)
throw anErrorOrAnException();
return round(pow(gold, n) / sq5);
}
I know some function names are not right, but the algorithm is there...
round(x) == floor(x + 0.5f)
pow(x, y) means x ^ y
gold is the golden number...
const float sq5 = (float)sqrt(5.0f);
const float gold = (float)(sqrt(1.25f) + 0.5f);
int fibonacci(int n)
{
if (n < 0)
throw anErrorOrAnException();
return round(pow(gold, n) / sq5);
}
I know some function names are not right, but the algorithm is there...
round(x) == floor(x + 0.5f)
pow(x, y) means x ^ y
gold is the golden number...
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement