How to explain cached fibonacci algorithm complexity - javascript

I'm trying to explain correctly cached fibonacci algorithm complexity. Here is the code (https://jsfiddle.net/msthhbgy/2/):
function allFib(n) {
var memo = [];
for (var i = 0; i < n; i++) {
console.log(i + ":" + fib(i, memo))
}
}
function fib(n, memo) {
if (n < 0) return 0;
else if (n === 1) return 1;
else if (memo[n]) return memo[n];
memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
return memo[n];
}
allFib(5);
The solution is taken from "Cracking the coding interview" and adapted to javascript.
So here is a "not very nice" tree of function calls
I was thinking like that: "The left most branch (bold one) is where the evaluation is happening" and it is definitely the number passed to the allFib function for the first time. So the complexity is O(n). Everything that is to the right will be taken from cache and will not require extra function calls". is it correct? also how to connect this to the tree "theory". The depth and the height of the tree in this case is 4 but not 5 (close to n but not it). I want the answer to be not intuitive but more reliable.

Here is a function that really uses the cache:
function Fibonacci() {
var memo = [0, 1];
this.callCount = 0;
this.calc = function(n) {
this.callCount++;
return n <= 0 ? 0
: memo[n] || (memo[n] = this.calc(n - 1) + this.calc(n - 2));
}
}
var fib = new Fibonacci();
console.log('15! = ', fib.calc(15));
console.log('calls made: ', fib.callCount);
fib.callCount = 0; // reset counter
console.log('5! = ', fib.calc(5));
console.log('calls made: ', fib.callCount);
fib.callCount = 0;
console.log('18! = ', fib.calc(18));
console.log('calls made: ', fib.callCount);
The number of function calls made is:
(n - min(i,n))*2+1
Where i is the last entry in memo.
This you can see as follows with the example of n = 18 and i = 15:
The calls are made in this order:
calc(18)
calc(17) // this.calc(n-1) with n=18
calc(16) // this.calc(n-1) with n=17
calc(15) // this.calc(n-1) with n=16, this can be returned from memo
calc(14) // this.calc(n-2) with n=16, this can be returned from memo
calc(15) // this.calc(n-2) with n=17, this can be returned from memo
calc(16) // this.calc(n-2) with n=18, this can be returned from memo
The general pattern is that this.calc(n-1) and this.calc(n-2) are called just as many as times (of course), with in addition the original call calc(n).
Here is an animation for when you call fib.calcfor the first time as fib.calc(5). The arrows show the calls that are made. The more to the left, the deeper the recursion. The bubbles are colored when the corresponding result is stored in memo:
This evidently is O(n) when i is a given constant.

First, check for negative n, and move the value to zero.
Then check if a value is cached, take the value. If not, assign the value to the cache and return the result.
For the special cases of n === 0 or n === 1 assign n.
function fibonacci(number) {
function f(n) {
return n in cache ?
cache[n] :
cache[n] = n === 0 || n === 1 ? n : f(n - 1) + f(n - 2);
}
var cache = [];
return f(number);
}
console.log(fibonacci(15));
console.log(fibonacci(5));
Part with predefined values in cache, as Thomas suggested.
function fibonacci(number) {
function f(n) {
return n in cache ?
cache[n] :
cache[n] = f(n - 1) + f(n - 2);
}
var cache = [0, 1];
return f(number);
}
console.log(fibonacci(15));
console.log(fibonacci(5));

Related

Dynamic Programming: Implementing a solution using memoization

As the question states, I am trying to solve a leetcode problem. The solutions are available online but, I want to implement my own solution. I have built my logic. Logic is totally fine. However, I am unable to optimize the code as the time limit is exceeding for the large numbers.
Here's my code:
let count = 0;
const climbingStairs = (n, memo = [{stairs: null}]) => {
if(n === memo[n]) {
count += memo[n].stairs;
}
if(n < 0) return;
if(n === 0) return memo[n].stairs = count++;
memo[n] = climbingStairs(n - 1, memo) + climbingStairs(n - 2, memo);
return memo[n];
}
climbingStairs(20); //running fine on time
climbingStairs(40); //hangs as the code isn't optimized
console.log(count); //the output for the given number
The code optimization using the memoization object is not working. I have tried multiple ways but still, facing issues. Any help would be appreciated in optimizing the code. Thanks!
no need for count value, you can memoize this way:
const climbStairs = (n, memo = []) => {
if(n <= 2) return n;
if(memo[n]) {
return memo[n];
}
memo[n] = climbStairs(n - 1, memo) + climbStairs(n - 2, memo);
return memo[n];
}
Actually, you do not store a value, but NaN to the array.
You need to return zero to get a numerical value for adding.
Further more, you assign in each call a new value, even if you already have this value in the array.
A good idea is to use only same types (object vs number) in the array and not mixed types, because you need a differen hndling for each type.
const climbingStairs = (n, memo = [1]) => {
if (n < 0) return 0;
return memo[n] ??= climbingStairs(n - 1, memo) + climbingStairs(n - 2, memo);
}
console.log(climbingStairs(5));
console.log(climbingStairs(20));
console.log(climbingStairs(40));

Find possible numbers in array that can sum to a target value

Given I have an array of numbers for example [14,6,10] - How can I find possible combinations/pairs that can add upto a given target value.
for example I have [14,6,10], im looking for a target value of 40
my expected output will be
10 + 10 + 6 + 14
14 + 14 + 6 + 6
10 + 10 + 10 + 10
*Order is not important
With that being said, this is what I tried so far:
function Sum(numbers, target, partial) {
var s, n, remaining;
partial = partial || [];
s = partial.reduce(function (a, b) {
return a + b;
}, 0);
if (s === target) {
console.log("%s", partial.join("+"))
}
for (var i = 0; i < numbers.length; i++) {
n = numbers[i];
remaining = numbers.slice(i + 1);
Sum(remaining, target, partial.concat([n]));
}
}
>>> Sum([14,6,10],40);
// returns nothing
>>> Sum([14,6,10],24);
// return 14+10
It is actually useless since it will only return if the number can be used only once to sum.
So how to do it?
You could add the value of the actual index as long as the sum is smaller than the wanted sum or proceed with the next index.
function getSum(array, sum) {
function iter(index, temp) {
var s = temp.reduce((a, b) => a + b, 0);
if (s === sum) result.push(temp);
if (s >= sum || index >= array.length) return;
iter(index, temp.concat(array[index]));
iter(index + 1, temp);
}
var result = [];
iter(0, []);
return result;
}
console.log(getSum([14, 6, 10], 40));
.as-console-wrapper { max-height: 100% !important; top: 0; }
For getting a limited result set, you could specify the length and check it in the exit condition.
function getSum(array, sum, limit) {
function iter(index, temp) {
var s = temp.reduce((a, b) => a + b, 0);
if (s === sum) result.push(temp);
if (s >= sum || index >= array.length || temp.length >= limit) return;
iter(index, temp.concat(array[index]));
iter(index + 1, temp);
}
var result = [];
iter(0, []);
return result;
}
console.log(getSum([14, 6, 10], 40, 5));
.as-console-wrapper { max-height: 100% !important; top: 0; }
TL&DR : Skip to Part II for the real thing
Part I
#Nina Scholz answer to this fundamental problem just shows us a beautiful manifestation of an algorithm. Honestly it confused me a lot for two reasons
When i try [14,6,10,7,3] with a target 500 it makes 36,783,575 calls to the iter function without blowing the call stack. Yet memory shows no significant usage at all.
My dynamical programming solution goes a little faster (or may be not) but there is no way it can do above case without exhousting the 16GB memory.
So i shelved my solution and instead started investigating her code a little further on dev tools and discoverd both it's beauty and also a little bit of it's shortcomings.
First i believe this algorithmic approach, which includes a very clever use of recursion, might possibly deserve a name of it's own. It's very memory efficient and only uses up memory for the constructed result set. The stack dynamically grows and shrinks continuoously up to nowhere close to it's limit.
The problem is, while being very efficient it still makes huge amounts of redundant calls. So looking into that, with a slight modification the 36,783,575 calls to iter can be cut down to 20,254,744... like 45% which yields a much faster code. The thing is the input array must be sorted ascending.
So here comes a modified version of Nina's algorithm. (Be patient.. it will take like 25 secs to finalize)
function getSum(array, sum) {
function iter(index, temp) {cnt++ // counting iter calls -- remove in production code
var s = temp.reduce((a, b) => a + b, 0);
sum - s >= array[index] && iter(index, temp.concat(array[index]));
sum - s >= array[index+1] && iter(index + 1, temp);
s === sum && result.push(temp);
return;
}
var result = [];
array.sort((x,y) => x-y); // this is a very cheap operation considering the size of the inpout array should be small for reasonable output.
iter(0, []);
return result;
}
var cnt = 0,
arr = [14,6,10,7,3],
tgt = 500,
res;
console.time("combos");
res = getSum(arr,tgt);
console.timeEnd("combos");
console.log(`source numbers are ${arr}
found ${res.length} unique ways to sum up to ${tgt}
iter function has been called ${cnt} times`);
Part II
Eventhough i was impressed with the performance, I wasn't comfortable with above solution for no solid reason that i can name. The way it works on side effects and the very hard to undestand double recursion and such disturbed me.
So here comes my approach to this question. This is many times more efficient compared to the accepted solution despite i am going functional in JS. We have still have room to make it a little faster with ugly imperative ways.
The difference is;
Given numbers: [14,6,10,7,3]
Target Sum: 500
Accepted Answer:
Number of possible ansers: 172686
Resolves in: 26357ms
Recursive calls count: 36783575
Answer Below
Number of possible ansers: 172686
Resolves in: 1000ms
Recursive calls count: 542657
function items2T([n,...ns],t){cnt++ //remove cnt in production code
var c = ~~(t/n);
return ns.length ? Array(c+1).fill()
.reduce((r,_,i) => r.concat(items2T(ns, t-n*i).map(s => Array(i).fill(n).concat(s))),[])
: t % n ? []
: [Array(c).fill(n)];
};
var cnt = 0, result;
console.time("combos");
result = items2T([14, 6, 10, 7, 3], 500)
console.timeEnd("combos");
console.log(`${result.length} many unique ways to sum up to 500
and ${cnt} recursive calls are performed`);
Another important point is, if the given array is sorted descending then the amount of recursive iterations will be reduced (sometimes greatly), allowing us to squeeze out more juice out of this lemon. Compare above with the one below when the input array is sorted descending.
function items2T([n,...ns],t){cnt++ //remove cnt in production code
var c = ~~(t/n);
return ns.length ? Array(c+1).fill()
.reduce((r,_,i) => r.concat(items2T(ns, t-n*i).map(s => Array(i).fill(n).concat(s))),[])
: t % n ? []
: [Array(c).fill(n)];
};
var cnt = 0, result;
console.time("combos");
result = items2T([14, 10, 7, 6, 3], 500)
console.timeEnd("combos");
console.log(`${result.length} many unique ways to sum up to 500
and ${cnt} recursive calls are performed`);

Random Fibonacci Generator

I'm trying to create a simple program in javascript where the Fibonacci square can be created by a random number sequence but I can't seem to connect both parts of my code. The first side being: the call for a random number and the second part: calculating the Fibonacci square.
var n = function getRandomNum() {
return Math.floor(Math.random()*100) +1;
}
function fib(x) {
if (x < 2) {
return x;
} else {
return fib(x - 1) + fib(x - 2);
}
}
console.log(fib(n));
Tell me where I'm going wrong. These are the errors I get when I run it.
RangeError: Maximum call stack size exceeded
at fib:7:13
at fib:11:12
at fib:11:12
at fib:11:12
at fib:11:12
at fib:11:12
Aside from not invoking the random number generator, you're using a very poorly optimized algorithm. If you think through all the redundant calls that need to take place, you'll see why the stack limit is reached.
var n = function getRandomNum() {
return Math.floor(Math.random() * 100) + 1;
}(); // <-- quick inline invocation... not normally how you'd use this.
console.log(n);
function fib(x) {
function _fib(x, a, b) {
if (x < 2) {
return a;
}
return _fib(x - 1, b, a + b);
}
return _fib(x, 0, 1);
}
console.log(fib(n));
Since you don't call n function, you should call it like the following.
var n = function getRandomNum() {
return Math.floor(Math.random()*100) +1;
}
function fib(x) {
if (x < 2) {
return x;
} else {
return fib(x - 1) + fib(x - 2);
}
}
console.log(fib(n));
But, there's a huge problem in your code, as #rock star mentioned, there's no any optimizing process in your code. That is why your code has caused the problem on memory leak
To avoid this, you can simply use memoization, click this link you don't have any clue on it.
Javascript Memoization Explanation?
So, your code can be improved like the folloiwng, by adapting memoization algorithm.
var n = function getRandomNum() {
return Math.floor(Math.random()*100) +1;
}
var result = [];
result[0] = 1;
result[1] = 1;
function fib(x) {
var ix, ixLen;
for(ix = 0, ixLen = x; ix < ixLen; ix++){
if(!result[ix]){
result[ix] = result[ix-2] + result[ix-1];
}
}
console.log('n:', x, ' result: ', result[ix-1]);
return result[ix-1];
}
console.log(fib(n()));
Compare the result with this site.
http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibtable.html

Get factorial of all the numbers of array recursively

I am trying to get factorial of all the numbers of array(recurArray) using recursion and without loops.
I am getting Error "Maximum call stack size exceeded"
I think there is some issue with the for loop logic, would be helpful if someone can explain the cause of error and how to fix it
Thanks.
//code
function recur(){
var n;
var result;
if(n == 1)
return 1;
var recurArray = [5,6,7,8,9];
for (var i = 0;i<recurArray.length;i++){
n = recurArray[i];
result = n * recur(n-1);
n=n-1;
}
console.log("val of n " + n + "value of i " + i);
return result;
}
recur();
Your recur() function should probably take n as an argument, otherwise n will never be 1 (if(n == 1) return 1;) and your function will keep calling itself until it crashes.
Try function recur(n){ instead.
As you have array, you should use loop.
function recur(x) {
if(x==0) {
return 1;
}
return x * recur(x-1);
}
function getFact() {
var recurArray = [5,6,7,8,9];
for (var i = 0;i<recurArray.length;i++){
console.log(recur(recurArray[i]));
}
}
getFact();
In Each occurence you reset the factorial so it keep rolling for fact(5) you need to have a function that calculate the factorial and an other one for the loop over your array like this :
function recur(n){
if(n == 1){
return 1;
} else {
return n* recur(n-1);
}
}
var recurArray = [5,6,7,8,9];
for (var i = 0;i<recurArray.length;i++){
n = recurArray[i];
result = recur(n);
console.log("factorial of n " + n + " is " + result);
}
Try something like this:
function factorial(number) {
var temp;
if(number <= 1) return 1;
temp = number * factorial(number - 1);
return temp;
}
In this case factorial(5); will return !5 . Recursive functions are not supposed to have loops inside(They can, but the execution time would be horrendous).
Also recursive functions call themselves with different parameters(otherwise you would overflow the browser stack). In your case you call recursive() an infinite amount of times and the loop always starts from 5 , infinitely. The passed parameter is what stops the recursion.

Javascript Fibonacci nth Term Optimization

I've become interested in algorithms lately, and the fibonacci sequence grabbed my attention due to its simplicity.
I've managed to put something together in javascript that calculates the nth term in the fibonacci sequence in less than 15 milliseconds after reading lots of information on the web. It goes up to 1476...1477 is infinity and 1478 is NaN (according to javascript!)
I'm quite proud of the code itself, except it's an utter monster.
So here's my question:
A) is there a faster way to calculate the sequence?
B) is there a faster/smaller way to multiply two matrices?
Here's the code:
//Fibonacci sequence generator in JS
//Cobbled together by Salty
m = [[1,0],[0,1]];
odd = [[1,1],[1,0]];
function matrix(a,b) {
/*
Matrix multiplication
Strassen Algorithm
Only works with 2x2 matrices.
*/
c=[[0,0],[0,0]];
c[0][0]=(a[0][0]*b[0][0])+(a[0][1]*b[1][0]);
c[0][1]=(a[0][0]*b[0][1])+(a[0][1]*b[1][1]);
c[1][0]=(a[1][0]*b[0][0])+(a[1][1]*b[1][0]);
c[1][1]=(a[1][0]*b[0][1])+(a[1][1]*b[1][1]);
m1=(a[0][0]+a[1][1])*(b[0][0]+b[1][1]);
m2=(a[1][0]+a[1][1])*b[0][0];
m3=a[0][0]*(b[0][1]-b[1][1]);
m4=a[1][1]*(b[1][0]-b[0][0]);
m5=(a[0][0]+a[0][1])*b[1][1];
m6=(a[1][0]-a[0][0])*(b[0][0]+b[0][1]);
m7=(a[0][1]-a[1][1])*(b[1][0]+b[1][1]);
c[0][0]=m1+m4-m5+m7;
c[0][1]=m3+m5;
c[1][0]=m2+m4;
c[1][1]=m1-m2+m3+m6;
return c;
}
function fib(n) {
mat(n-1);
return m[0][0];
}
function mat(n) {
if(n > 1) {
mat(n/2);
m = matrix(m,m);
}
m = (n%2<1) ? m : matrix(m,odd);
}
alert(fib(1476)); //Alerts 1.3069892237633993e+308
The matrix function takes two arguments: a and b, and returns a*b where a and b are 2x2 arrays.
Oh, and on a side note, a magical thing happened...I was converting the Strassen algorithm into JS array notation and it worked on my first try! Fantastic, right? :P
Thanks in advance if you manage to find an easier way to do this.
Don't speculate, benchmark:
edit: I added my own matrix implementation using the optimized multiplication functions mentioned in my other answer. This resulted in a major speedup, but even the vanilla O(n^3) implementation of matrix multiplication with loops was faster than the Strassen algorithm.
<pre><script>
var fib = {};
(function() {
var sqrt_5 = Math.sqrt(5),
phi = (1 + sqrt_5) / 2;
fib.round = function(n) {
return Math.floor(Math.pow(phi, n) / sqrt_5 + 0.5);
};
})();
(function() {
fib.loop = function(n) {
var i = 0,
j = 1;
while(n--) {
var tmp = i;
i = j;
j += tmp;
}
return i;
};
})();
(function () {
var cache = [0, 1];
fib.loop_cached = function(n) {
if(n >= cache.length) {
for(var i = cache.length; i <= n; ++i)
cache[i] = cache[i - 1] + cache[i - 2];
}
return cache[n];
};
})();
(function() {
//Fibonacci sequence generator in JS
//Cobbled together by Salty
var m;
var odd = [[1,1],[1,0]];
function matrix(a,b) {
/*
Matrix multiplication
Strassen Algorithm
Only works with 2x2 matrices.
*/
var c=[[0,0],[0,0]];
var m1=(a[0][0]+a[1][1])*(b[0][0]+b[1][1]);
var m2=(a[1][0]+a[1][1])*b[0][0];
var m3=a[0][0]*(b[0][1]-b[1][1]);
var m4=a[1][1]*(b[1][0]-b[0][0]);
var m5=(a[0][0]+a[0][1])*b[1][1];
var m6=(a[1][0]-a[0][0])*(b[0][0]+b[0][1]);
var m7=(a[0][1]-a[1][1])*(b[1][0]+b[1][1]);
c[0][0]=m1+m4-m5+m7;
c[0][1]=m3+m5;
c[1][0]=m2+m4;
c[1][1]=m1-m2+m3+m6;
return c;
}
function mat(n) {
if(n > 1) {
mat(n/2);
m = matrix(m,m);
}
m = (n%2<1) ? m : matrix(m,odd);
}
fib.matrix = function(n) {
m = [[1,0],[0,1]];
mat(n-1);
return m[0][0];
};
})();
(function() {
var a;
function square() {
var a00 = a[0][0],
a01 = a[0][1],
a10 = a[1][0],
a11 = a[1][1];
var a10_x_a01 = a10 * a01,
a00_p_a11 = a00 + a11;
a[0][0] = a10_x_a01 + a00 * a00;
a[0][1] = a00_p_a11 * a01;
a[1][0] = a00_p_a11 * a10;
a[1][1] = a10_x_a01 + a11 * a11;
}
function powPlusPlus() {
var a01 = a[0][1],
a11 = a[1][1];
a[0][1] = a[0][0];
a[1][1] = a[1][0];
a[0][0] += a01;
a[1][0] += a11;
}
function compute(n) {
if(n > 1) {
compute(n >> 1);
square();
if(n & 1)
powPlusPlus();
}
}
fib.matrix_optimised = function(n) {
if(n == 0)
return 0;
a = [[1, 1], [1, 0]];
compute(n - 1);
return a[0][0];
};
})();
(function() {
var cache = {};
cache[0] = [[1, 0], [0, 1]];
cache[1] = [[1, 1], [1, 0]];
function mult(a, b) {
return [
[a[0][0] * b[0][0] + a[0][1] * b[1][0],
a[0][0] * b[0][1] + a[0][1] * b[1][1]],
[a[1][0] * b[0][0] + a[1][1] * b[1][0],
a[1][0] * b[0][1] + a[1][1] * b[1][1]]
];
}
function compute(n) {
if(!cache[n]) {
var n_2 = n >> 1;
compute(n_2);
cache[n] = mult(cache[n_2], cache[n_2]);
if(n & 1)
cache[n] = mult(cache[1], cache[n]);
}
}
fib.matrix_cached = function(n) {
if(n == 0)
return 0;
compute(--n);
return cache[n][0][0];
};
})();
function test(name, func, n, count) {
var value;
var start = Number(new Date);
while(count--)
value = func(n);
var end = Number(new Date);
return 'fib.' + name + '(' + n + ') = ' + value + ' [' +
(end - start) + 'ms]';
}
for(var func in fib)
document.writeln(test(func, fib[func], 1450, 10000));
</script></pre>
yields
fib.round(1450) = 4.8149675025003456e+302 [20ms]
fib.loop(1450) = 4.81496750250011e+302 [4035ms]
fib.loop_cached(1450) = 4.81496750250011e+302 [8ms]
fib.matrix(1450) = 4.814967502500118e+302 [2201ms]
fib.matrix_optimised(1450) = 4.814967502500113e+302 [585ms]
fib.matrix_cached(1450) = 4.814967502500113e+302 [12ms]
Your algorithm is nearly as bad as uncached looping. Caching is your best bet, closely followed by the rounding algorithm - which yields incorrect results for big n (as does your matrix algorithm).
For smaller n, your algorithm performs even worse than everything else:
fib.round(100) = 354224848179263100000 [20ms]
fib.loop(100) = 354224848179262000000 [248ms]
fib.loop_cached(100) = 354224848179262000000 [6ms]
fib.matrix(100) = 354224848179261900000 [1911ms]
fib.matrix_optimised(100) = 354224848179261900000 [380ms]
fib.matrix_cached(100) = 354224848179261900000 [12ms]
There is a closed form (no loops) solution for the nth Fibonacci number.
See Wikipedia.
There may well be a faster way to calculate the values but I don't believe it's necessary.
Calculate them once and, in your program, output the results as the fibdata line below:
fibdata = [1,1,2,3,5,8,13, ... , 1.3069892237633993e+308]; // 1476 entries.
function fib(n) {
if ((n < 0) || (n > 1476)) {
** Do something exception-like or return INF;
}
return fibdata[n];
}
Then, that's the code you ship to your clients. That's an O(1) solution for you.
People often overlook the 'caching' solution. I once had to write trigonometry routines for an embedded system and, rather than using infinite series to calculate them on the fly, I just had a few lookup tables, 360 entries in each for each of the degrees of input.
Needless to say, it screamed along, at the cost of only about 1K of RAM. The values were stored as 1-byte entries, [actual value (0-1) * 16] so we could just do a lookup, multiply and bit shift to get the desired value.
My previous answer got a bit crowded, so I'll post a new one:
You can speed up your algorithm by using vanilla 2x2 matrix multiplication - ie replace your matrix() function with this:
function matrix(a, b) {
return [
[a[0][0] * b[0][0] + a[0][1] * b[1][0],
a[0][0] * b[0][1] + a[0][1] * b[1][1]],
[a[1][0] * b[0][0] + a[1][1] * b[1][0],
a[1][0] * b[0][1] + a[1][1] * b[1][1]]
];
}
If you care for accuracy and speed, use the caching solution. If accuracy isn't a concern, but memory consumption is, use the rounding solution. The matrix solution only makes sense if you want results for big n fast, don't care for accuracy and don't want to call the function repeatedly.
edit: You can even further speed up the computation if you use specialised multiplication functions, eliminate common subexpressions and replace the values in the existing array instead of creating a new array:
function square() {
var a00 = a[0][0],
a01 = a[0][1],
a10 = a[1][0],
a11 = a[1][1];
var a10_x_a01 = a10 * a01,
a00_p_a11 = a00 + a11;
a[0][0] = a10_x_a01 + a00 * a00;
a[0][1] = a00_p_a11 * a01;
a[1][0] = a00_p_a11 * a10;
a[1][1] = a10_x_a01 + a11 * a11;
}
function powPlusPlus() {
var a01 = a[0][1],
a11 = a[1][1];
a[0][1] = a[0][0];
a[1][1] = a[1][0];
a[0][0] += a01;
a[1][0] += a11;
}
Note: a is the name of the global matrix variable.
Closed form solution in JavaScript: O(1), accurate up for n=75
function fib(n){
var sqrt5 = Math.sqrt(5);
var a = (1 + sqrt5)/2;
var b = (1 - sqrt5)/2;
var ans = Math.round((Math.pow(a, n) - Math.pow(b, n))/sqrt5);
return ans;
}
Granted, even multiplication starts to take its expense when dealing with huge numbers, but this will give you the answer. As far as I know, because of JavaScript rounding the values, it's only accurate up to n = 75. Past that, you'll get a good estimate, but it won't be totally accurate unless you want to do something tricky like store the values as a string then parse those as BigIntegers.
How about memoizing the results that where already calculated, like such:
var IterMemoFib = function() {
var cache = [1, 1];
var fib = function(n) {
if (n >= cache.length) {
for (var i = cache.length; i <= n; i++) {
cache[i] = cache[i - 2] + cache[i - 1];
}
}
return cache[n];
}
return fib;
}();
Or if you want a more generic memoization function, extend the Function prototype:
Function.prototype.memoize = function() {
var pad = {};
var self = this;
var obj = arguments.length > 0 ? arguments[i] : null;
var memoizedFn = function() {
// Copy the arguments object into an array: allows it to be used as
// a cache key.
var args = [];
for (var i = 0; i < arguments.length; i++) {
args[i] = arguments[i];
}
// Evaluate the memoized function if it hasn't been evaluated with
// these arguments before.
if (!(args in pad)) {
pad[args] = self.apply(obj, arguments);
}
return pad[args];
}
memoizedFn.unmemoize = function() {
return self;
}
return memoizedFn;
}
//Now, you can apply the memoized function to a normal fibonacci function like such:
Fib = fib.memoize();
One note to add is that due to technical (browser security) constraints, the arguments for memoized functions can only be arrays or scalar values. No objects.
Reference: http://talideon.com/weblog/2005/07/javascript-memoization.cfm
To expand a bit on Dreas's answer:
1) cache should start as [0, 1]
2) what do you do with IterMemoFib(5.5)? (cache[5.5] == undefined)
fibonacci = (function () {
var FIB = [0, 1];
return function (x) {
if ((typeof(x) !== 'number') || (x < 0)) return;
x = Math.floor(x);
if (x >= FIB.length)
for (var i = FIB.length; i <= x; i += 1)
FIB[i] = FIB[i-1] + FIB[i-2];
return FIB[x];
}
})();
alert(fibonacci(17)); // 1597 (FIB => [0, 1, ..., 1597]) (length = 17)
alert(fibonacci(400)); // 1.760236806450138e+83 (finds 18 to 400)
alert(fibonacci(1476)); // 1.3069892237633987e+308 (length = 1476)
If you don't like silent errors:
// replace...
if ((typeof(x) !== 'number') || (x < 0)) return;
// with...
if (typeof(x) !== 'number') throw new TypeError('Not a Number.');
if (x < 0) throw new RangeError('Not a possible fibonacci index. (' + x + ')');
Here is a very fast solution of calculating the fibonacci sequence
function fib(n){
var start = Number(new Date);
var field = new Array();
field[0] = 0;
field[1] = 1;
for(var i=2; i<=n; i++)
field[i] = field[i-2] + field[i-1]
var end = Number(new Date);
return 'fib' + '(' + n + ') = ' + field[n] + ' [' +
(end - start) + 'ms]';
}
var f = fib(1450)
console.log(f)
I've just written my own little implementation using an Object to store already computed results. I've written it in Node.JS, which needed 2ms (according to my timer) to calculate the fibonacci for 1476.
Here's the code stripped down to pure Javascript:
var nums = {}; // Object that stores already computed fibonacci results
function fib(n) { //Function
var ret; //Variable that holds the return Value
if (n < 3) return 1; //Fib of 1 and 2 equal 1 => filtered here
else if (nums.hasOwnProperty(n)) ret = nums[n]; /*if the requested number is
already in the object nums, return it from the object, instead of computing */
else ret = fib( n - 2 ) + fib( n - 1 ); /* if requested number has not
yet been calculated, do so here */
nums[n] = ret; // add calculated number to nums objecti
return ret; //return the value
}
//and finally the function call:
fib(1476)
EDIT: I did not try running this in a Browser!
EDIT again: now I did. try the jsfiddle: jsfiddle fibonacci Time varies between 0 and 2ms
Much faster algorithm:
const fib = n => fib[n] || (fib[n-1] = fib(n-1)) + fib[n-2];
fib[0] = 0; // Any number you like
fib[1] = 1; // Any number you like

Categories

Resources