The Fibonacci sequence generates numbers that grow very quickly. It turns out that the way you’re doing, each recursive call will create other recursive calls that create other recursive calls that create other recursive calls... until at the end of each recursive call, a 0 or 1 result is produced.
Here is an example of what happens, with fibonacci(8)
:
In this table above, the left column represents the first call of fibonacci(8)
. It reduces to two other calls to fibonacci(7)
and the fibonacci(6)
, that are in the second column. Each of these calls will subdivide several times until at the end we will have a lot of zeros and a.
With this we can form a call tree. In the leaves of these trees we have zeros and ones that will be returned to the calling functions and will be summed up to provide the final result, which is 21.
Note that we have the number 1 appearing on 21 sheets. We also have the number 0 appearing on 13 sheets. 13 is also the result of fibonacci(7)
. In total there are 34 leaves, which is the result of fibonacci(9)
.
If you mount this tree with other numbers, you will see that for any number n
, the number of sheets shall be fibonacci(n + 1)
, the number of sheets with 1 shall be fibonacci(n)
and the number of sheets with 0 will be fibonacci(n - 1)
.
Each of these sheets requires a processing to be achieved. And in the end, we can see that we’re actually just adding up the results of a lot of zeros and ones. That’s a pretty large number of sums. In total the sum operation happens fibonacci(n + 1) - 1
times.
Now, let’s take the result of fibonacci(80)
, which is 23,416,728,348,467,684. This means that your program will take forever to add up a lot of zeros and ones to reach that number. This is why the program is slow. Using the approach demonstrated in reply from Antonio Carlos, this is solved. To calculate fibonacci(n)
, in fact are only needed (n - 1)
sums. That is, to calculate fibonacci(80)
we only need 79 sums actually.
If we look at this tree up there, we see that a lot of results are recalculated over and over and over again. Therefore, if we store intermediate results already obtained previously in a table, we can later consult them instead of recalculate them, leaving the program more efficient. This is the principle of dynamic programming. To calculate the fibonacci(n)
, we have to calculate first the fibonacci(n - 1)
, until then ok. But when calculating the fibonacci(n - 1)
, we will also have calculated the fibonacci(n - 2)
. This way, we don’t need to recalculate the fibonacci(n - 2)
, if we have saved its result when calculating the fibonacci(n - 1)
, just add up this saved result, which avoids having to repurchase it.
In the program of reply from Antonio Carlos, it uses only the variables a
and b
. This is because in fact we only need the two most recent results of the table, because when calculating fibonacci(n)
, these two oldest results will be the fibonacci(n - 1)
and the fibonacci(n - 2)
. This way, anything after the fibonacci(n - 3)
can be forgotten because it will no longer be necessary. Thus, we can keep the table only with the last two results when representing it only with two variables, a
and b
. The variable f
is just an auxiliary variable so that nothing is lost while the table is being changed, which is evidenced if its code is rewritten like this:
var fibonacci = function(n) {
var a = 0, b = 1;
for (var i = 2; i <= n; i++) {
var f = a;
a = b;
b += f;
}
return b;
};
Thank you for such a complete reply.
– Marcus Becker
Victor Stafusa, cool (+1). I don’t know javascript. You don’t want to think about a table with the team(Fib(80)) of the variants that have been appearing? :)
– JJoao
@Jjoao I don’t know if I understand what you want. Want to do an experiment to measure the time of each algorithm?
– Victor Stafusa
I think he wants you to do this table with 80 instead of 8 :)
– Marcus Becker
I think it would be nice for the operator
++
stand on the left side:++i
instead ofi++
, doesn’t make much difference, but it will cause extra optimization anyway.– Klaider