Add Two Number leetcode algo - javascript

I was doing following leetCode Problem: https://leetcode.com/problems/add-two-numbers/
And I am not sure why one of my test case is failing
So the question is
You are given two non-empty linked lists representing two non-negative
integers. The digits are stored in reverse order and each of their
nodes contain a single digit. Add the two numbers and return it as a
linked list.
You may assume the two numbers do not contain any leading zero, except
the number 0 itself.
For which I have written following algo
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* #param {ListNode} l1
* #param {ListNode} l2
* #return {ListNode}
*/
const makeLinkedList = (inArr, i) => {
if (i < 0) return null
return { val:inArr[i], next:makeLinkedList(inArr, i-1)}
}
var addTwoNumbers = function(l1, l2) {
let sum = 0
let i = 1
while(l1 || l2) {
if (l1 && l2) {
sum = sum + l1.val*i + l2.val*i
l1 = l1.next
l2 = l2.next
} else {
if (l1) {
sum = l1.val*i + sum
l1 = l1.next
}
if (l2) {
sum = l2.val*i + sum
l2 = l2.next
}
}
i = i*10
}
const sumToString = sum.toLocaleString('fullwide', {useGrouping:false});
return makeLinkedList(sumToString, sumToString.length-1)
};
The reason in the above code I have used while loop instead of recursively calling functions is mainly to make it more optimized.
anyway, For the following input, my test case is failing
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]
[5,6,4]
i.e my output is coming to be [0,3,NaN,NaN,1] instead of [6,6,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]
As a note, leetCode compiler will convert array to linkedlist on input. Can someone help me in figuring out why my input might be failing?

When JavaScript stringifies a number in scientific notation, there will be a + sign for positive exponents. That sequence you see is 1E+30, the NaNs are standing for + and E (because of the reverted order). In fact you could have put a console.log(sum) or console.log(sumToString) and catch the issue without knowing this, just simply seeing what is there.
Not all languages tell you the maximum value they can store without loss in precision, but JavaScript in particular does, Number.MAX_SAFE_INTEGER contains the value 9 007 199 254 740 991 so it is a bit more than 9E+15, far less than 1 + 1E+30 (the longer number).
What you are expected to do is to add the numbers like you have learned in elementary school: add two digits, write one digit, and see if there is an 1 to carry to the next digit-pair you are going to add.
Iterative version:
function makeLinkedList(arr,i){
i=i || 0;
return i<arr.length?{val:arr[i], next:makeLinkedList(arr,i+1)}:null;
}
var addTwoNumbers = function(l1, l2) {
var snt={next:null};
var cur=snt;
var carry=0;
while(l1 || l2 || carry){
cur.next={next:null};
cur=cur.next;
var sum=(l1?l1.val:0)+(l2?l2.val:0)+carry;
if(sum<10){
cur.val=sum;
carry=0;
} else {
cur.val=sum-10;
carry=1;
}
l1=l1?l1.next:null;
l2=l2?l2.next:null;
}
return snt.next;
}
var a=[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1];
var b=[5,6,4];
console.log(addTwoNumbers(makeLinkedList(a),makeLinkedList(b)));
a=[9,9];
b=[1,9];
console.log(addTwoNumbers(makeLinkedList(a),makeLinkedList(b)));
Recursive version:
function makeLinkedList(arr,i){
i=i || 0;
return i<arr.length?{val:arr[i], next:makeLinkedList(arr,i+1)}:null;
}
var addTwoNumbers = function(l1, l2, carry) {
if(!(l1 || l2 || carry))
return null;
carry=carry || 0;
var sum=(l1?l1.val:0)+(l2?l2.val:0)+carry;
return {
val: sum % 10,
next: addTwoNumbers(l1?l1.next:null,l2?l2.next:null,sum>9?1:0)
};
}
var a=[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1];
var b=[5,6,4];
console.log(addTwoNumbers(makeLinkedList(a),makeLinkedList(b)));
a=[9,9];
b=[1,9];
console.log(addTwoNumbers(makeLinkedList(a),makeLinkedList(b)));

Solution for the problem in JavaScript.
var addTwoNumbers = function (l1, l2) {
let reminder = 0;
let l1Node = l1;
let l2Node = l2;
let list = new ListNode(0);
let currentNode = list;
while (l1Node || l2Node) {
const valueL1 = l1Node ? l1Node.val : 0;
const valueL2 = l2Node ? l2Node.val : 0;
let sum = valueL1 + valueL2 + reminder;
reminder = 0;
if (sum > 9) {
reminder = Math.floor(sum / 10);
sum = sum % 10;
}
currentNode.next = new ListNode(sum);
currentNode = currentNode.next;
l1Node = l1Node ? l1Node.next : null;
l2Node = l2Node ? l2Node.next : null;
}
if (reminder != 0) {
currentNode.next = new ListNode(reminder);
currentNode = currentNode.next;
}
return list.next;
};
function ListNode(val, next) {
this.val = (val === undefined ? 0 : val)
this.next = (next === undefined ? null : next)
}
const l1 = new ListNode(2, new ListNode(4, new ListNode(3)));
const l2 = new ListNode(5, new ListNode(6))
const res = addTwoNumbers(l1, l2);
console.log(res);

Related

Why does my linked list code not work in a modular reusable JavaScript function?

Why does my linked list solution fail when I make my code more modular?
I am tackling question 2 on Leetcode "Add 2 numbers" in linked list format.
Here is the question:
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
I have a working solution with repetitive code.
When I abstract out the body of my last two functions into a reusable function, my solution fails. Why is this?
One assumption I am making is that linked list nodes are objects and should therefore be passed by reference. At least in JavaScript.
Here is my solution that succeeds (before making the code more modular)...
var addTwoNumbers = function(l1, l2) {
let l3 = new ListNode(0, null);
let head = l3;
let carry = 0;
while (l1 != null && l2 != null) {
l3.next = new ListNode(carry, null);
l3 = l3.next;
let sum = l1.val + l2.val + l3.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
l3.val = ones;
l1 = l1.next;
l2 = l2.next;
}
while (l1 != null) {
l3.next = new ListNode(carry, null);
l3 = l3.next;
let sum = l1.val + l3.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
l3.val = ones;
l1 = l1.next;
}
while (l2 != null) {
l3.next = new ListNode(carry, null);
l3 = l3.next;
let sum = l2.val + l3.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
l3.val = ones;
l2 = l2.next;
}
if (carry == 1) {
l3.next = new ListNode(carry, null);
}
return head.next;
};
Here is my solution that fails...
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* #param {ListNode} l1
* #param {ListNode} l2
* #return {ListNode}
*/
var addTwoNumbers = function(l1, l2) {
let l3 = new ListNode(0, null);
let head = l3;
let carry = 0;
while (l1 != null && l2 != null) {
l3.next = new ListNode(carry, null);
l3 = l3.next;
let sum = l1.val + l2.val + l3.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
l3.val = ones;
l1 = l1.next;
l2 = l2.next;
}
while (l1 != null) {
carry = addRemainingNodes(l1, l3, carry);
}
while (l2 != null) {
carry = addRemainingNodes(l2, l3, carry);
}
if (carry == 1) {
l3.next = new ListNode(carry, null);
}
return head.next;
};
function addRemainingNodes(la, lb, carry) {
lb.next = new ListNode(carry, null);
lb = lb.next;
let sum = la.val + lb.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
lb.val = ones;
la = la.next;
return carry;
}
One assumption I am making is that linked list nodes are objects and should therefore be passed by reference.
It is true that they are objects. Variables can have references to those objects. This is not something specific that happens when an argument is passed to a function. So for instance, l3 is a reference. It is this reference that is passed by value to the function, and the local variable lb receives this as its own value (the object reference is copied). When that function assigns to lb, then this only affects that local variable... not to the variable that was used to pass this value to the function.
As a rule of thumb: when a JavaScript function assigns a value to one of its parameter variables, this only has an effect to that local variable1.
However, when a function mutates a property of a parameter variable, then this will affect the object that was passed as argument.
So concluding, there is no pass-by-reference as can be done in C++. JavaScript uses the pass-by-value mechanics, taking into account that the value of an object really is a reference.
Avoiding code reuse
In your case, the treatment of l3 should be like you treat carry. Just like the function returns carry which got re-assigned, so also it should return l3. This you could do by returning an array with these two values. And then you can use a destructuring assignment at the calling side. This honestly does not look so elegant, but there is a different way to avoid code repetition:
Consider that it will never happen that both the second and the third while loop will make iterations. This is because at most one of l1 and l2 can be non null after the first loop finishes.
So make abstraction of this difference between l1 and l2 and use just one loop to replace these two loops:
let lrest = l1 || l2; // This will select the non-null list if there is one
while (lrest != null) {
l3.next = new ListNode(carry, null);
l3 = l3.next;
let sum = lrest.val + l3.val;
let ones = sum % 10;
carry = Math.floor(sum / 10);
l3.val = ones;
lrest = lrest.next;
}
1Rare exceptions to this rule exist. There are some alias behaviours like how arguments works in non-strict mode.

Adding value 0 to linked list node , Every other value works only number 0 doesnt work

I have two linked lists and I am creating a third list were every node is the sum of the nodes of list1 and list2 of the same index. It works fine, however when the sum of two nodes is greater than 9, say it's 15, then I subtract 15 - 10 = 5. This will become my current sum. I add this value to the next sum, say if the next sum is 4 then it will be 4+5 = 9.
The issue is when the sum = 10, then it will become 0. But when it's zero it refuses to create and append a new node to the list.
Here is my code:
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* #param {ListNode} l1
* #param {ListNode} l2
* #return {ListNode}
*/
function add(val){ //returns new node
console.log(val);
let node = new ListNode() ;
node = new ListNode(val , null)
if(!head){
head = tail = node;
head.next = null;
tail.next = null;
}
else{
tail.next = node;
node.next = null;
}
return node;
}
let head , tail;
var addTwoNumbers = function(l1, l2) {
let answer = "";
let sum ;
let node = null;
let isLarge = false;
while(l1 || l2){ //looping while any node exists
sum = 0; //initializing sum to 0
if(l1 && !l2)sum += l1.val;
else if(l2 && !l1) sum += l2.val;
else sum += l1.val + l2.val;
if(isLarge){ //if prev sum was > 10
sum++;
isLarge = false;
}
if(sum > 9){ //if sum > 10
sum = sum - 10;
isLarge = true;
}
add(sum);
l1 = l1.next;
l2 = l2.next;
}
return head;
};
There are the following issues:
The add function does not update the tail reference, except when the list was empty. But this should happen always: the tail should reference the added node.
The main loop advances l1 and l2 even though one of them could be null. When that happens, an exception occurs. This update should only be done for the references that are not null
Even when l1 and l2 have become null, there might still be a carry, i.e. isLarge could be true after the loop ends. In that case you need to add an extra node to the result list, with value 1. You would do this after the loop.
You will get into problems when this code is run several times (for instance as part of a test suite): the global variables will retain the information from the previous call of addTwoNumbers, and so subsequent results will be wrong. You should not use global variables. Adapt your code such that head and tail are local variables. You would then also need to adapt the function add, since it can modify both head and tail. It will probably be easier to just integrate that add-logic inside addTwoNumbers.
When those two things are fixed, you'll get the correct result.
Here is the code where these issues are fixed, and some other things are done in a more compact way:
function ListNode(val, next) {
this.val = (val===undefined ? 0 : val)
this.next = (next===undefined ? null : next)
}
var addTwoNumbers = function(l1, l2) {
let sum;
let head = null;
let tail = null;
let carry = 0;
while (l1 || l2) {
sum = carry;
if (l1) {
sum += l1.val;
l1 = l1.next;
}
if (l2) {
sum += l2.val;
l2 = l2.next;
}
carry = +(sum > 9);
sum %= 10;
let node = new ListNode(sum);
if (head) {
tail.next = node;
} else {
head = node;
}
tail = node;
}
if (carry) {
tail.next = new ListNode(1);
}
return head;
};
// Some utility functions for this demo:
function from(...arr) {
let head;
for (let val of arr.reverse()) {
head = new ListNode(val, head);
}
return head;
}
function * iter(lst) {
while (lst) {
yield lst.val;
lst = lst.next;
}
}
// Demo
let l1 = from(2, 0, 1, 9);
let l2 = from(8, 4, 3, 1);
let l3 = addTwoNumbers(l1, l2);
console.log(...iter(l3)); // 0 5 4 0 1

Identify if a value is a Perfect Square and if so, then push it into an empty array

I'm trying to identify if a value is a Perfect Square and if that's the case, I want to push it into an array. I know that there is a built-in function that allows for it but I want to create an algorithm that does it. :)
Input: num = 16
Output: [4]
Example 2:
Input: num = 25
Output: [5]
Example 2:
Input: num = 14
Output: []
var isPerfectSquare = function(value) {
var perfectSquareVal = []
var highestValue = value;
var lowestValue = 0;
while (lowestValue < highestValue) {
var midpoint = 1 + Math.floor((highestValue + lowestValue)/2);
if (midpoint * midpoint === value) {
perfectSquareVal.push(midpoint);
} else if (midpoint * midpoint > value) {
highestValue = midpoint;
} else if (midpoint * midpoint < value) {
lowestValue = midpoint;
}
}
console.log(perfectSquareVal);
};
isPerfectSquare(16);
That seems really complicated to check if a number is a square, you could simply check if the square root is an Integer:
var isPerfectSquare = function(value) {
return Number.isInteger(Math.sqrt(value));
}
And if the function returns true, then push to array.
You could change the algorithm a bit by
taking the arthmetic mean with a flored value,
return if the product is found (why an array for the result?),
check only the greater oroduct because the smaller one is included in the check for equalness,
use decremented/incremented values, becaus the actual value is wrong,
keep a pure function, take ouput to the outside.
var isPerfectSquare = function (value) {
var highestValue = value,
lowestValue = 0;
while (lowestValue < highestValue) {
let midpoint = Math.floor((highestValue + lowestValue) / 2),
product = midpoint * midpoint;
if (product === value) return midpoint;
if (product > value) highestValue = midpoint - 1;
else lowestValue = midpoint + 1;
}
};
console.log(isPerfectSquare(25));
console.log(isPerfectSquare(250));

Adding float values in javascript

I have had problems with the conditional 0.1 + 0.2 !== 0.3. I tried 0.0001 + 0.0002 and this not equal 0.03. As I know, we can use toFixed to solve this problem. But is there any solution to resolve this problem dynamically? Because with 0.1 + 0.2 we use toFixed(2) and 0.0001 + 0.0002 uses toFixed(4).
You could extend Math to include a function to do the math. The below takes two floats, determines the greatest number of decimal places and then based on that does the math then does a toFixed using the greatest number of decimal places.
Math.addFloats = function (f1,f2){
//Helper function to find the number of decimal places
function findDec(dec){
var count = 0;
while(dec%1){
dec*=10;
count++;
}
return count;
}
//Determine the greatest number of decimal places
var dec1 = findDec(f1);
var dec2 = findDec(f2);
var fixed = dec1>dec2 ? dec1 : dec2;
//do the math then do a toFixed, could do a toPrecision also
var n = (f1+f2).toFixed(fixed);
return +n;
}
console.log( Math.addFloats(0.1,0.2) == 0.3 ); //evaluates to true
console.log( Math.addFloats(1/3,1/7) ); //prints 0.47619047619047616
console.log( 1/3 + 1/7 ); //prints 0.47619047619047616
Havent fully tested it but doing some preliminary tests shows it works dynamically, could probably modify it to do other maths, but would probably have to change the decimal count check when doing divides/multiples etc
NOTE: this does not seem to count decimal places well for e notation, ie 2e-14 results in like 30, when it should be 14
EDIT: changing the findDec function to this answers version of finding decimals places seems to be better at determining the correct number of decimal places for different types of numbers
function findDec(f1){
function isInt(n){
return typeof n === 'number' &&
parseFloat(n) == parseInt(n, 10) && !isNaN(n);
}
var a = Math.abs(f1);
f1 = a, count = 1;
while(!isInt(f1) && isFinite(f1)){
f1 = a * Math.pow(10,count++);
}
return count-1;
}
(a) if you are dealing with (say) dollars, the best sol'n is to do everything in cents, using ints. (This only works if you never deal with fractions of a penny.)
(b) in any language, treat doubles/floats as "a good approximation of the actual value", and never compare with ==. Instead write a helper
double nearlyEqual(x,y,tolerance=0.00001) {
return abs(x-y) < tolerance*max(abs(x),abs(y)); }
(warning: untested code).
Thank #Patrick so much. I have create a new code to add multiple float numbers based on your code. It's:
/**
* Find the number of decimal places
* #method findDec
* #param {Float|Number} dec
* #return {Number}
*/
var findDec = function (dec) {
var count = 0;
while (dec % 1) {
dec *= 10;
count++;
}
return count;
};
/**
* Find the greatest number of decimal places
* #method findFixed
* #param {Float|Number} dec
* #return {Number}
*/
var findFixed = function () {
var fixed = [];
for (var i = 0, arg; arg = arguments[i]; i++) {
fixed.push(findDec(arg));
}
return Math.max.apply(this, fixed)
};
/**
* Calculate total
* #method findFixed
* #param {Float|Number}
* #return {Float|Number}
*/
var calculate = function () {
var total = 0;
for (var i = 0, arg; arg = arguments[i]; i++) {
total += arg;
}
return total;
}
/**
* Add float number
* #method addNumber
* #param {Float|Number}
* #return {Float|Number}
*/
Math.addNumber = function() {
//Determine the greatest number of decimal places
var fixed = findFixed.apply(this, arguments);
var total = calculate.apply(this, arguments);
//do the math then do a toFixed, could do a toPrecision also
return +total.toFixed(fixed);
}
use Number.prototype with custom like this :
Number.prototype.lenDecimalPoint = function(val){
var decStr = val.toString().match(/\.\d*/);
if(decStr && decStr.length > 0) {
return decStr[0].replace().replace('.','').length;
} else {
return 0;
}
}
Number.prototype.getVal = function(val, stdDec10Val){
var dec10ValLog = Math.log10(stdDec10Val);
var thisValDecPoint = this.lenDecimalPoint(val);
var thisValStr = val.toString();
thisValStr = thisValStr.replace('/^0\./','');
thisValStr = thisValStr.replace('.','');
thisValStr += Math.pow(10 ,dec10ValLog - thisValDecPoint).toString().replace('1','');
return Number(thisValStr);
}
Number.prototype.getDec10Val = function(val1, val2){
var thisDecPoint = this.lenDecimalPoint(val1);
var newNumValDecPoint = this.lenDecimalPoint(val2);
var decPoint = thisDecPoint > newNumValDecPoint ? thisDecPoint : newNumValDecPoint;
return Math.pow(10,decPoint);
}
Number.prototype.add = function(newVal) {
newVal = Number(newVal)
var dec10Val = this.getDec10Val(this, newVal);
var thisIntVal = this.getVal(this, dec10Val);
var newIntVal = this.getVal(newVal,dec10Val);
return Number(((thisIntVal) + (newIntVal))/dec10Val);
}
Number.prototype.sub = function(newVal) {
newVal = Number(newVal)
var dec10Val = this.getDec10Val(this, newVal);
var thisIntVal = this.getVal(this, dec10Val);
var newIntVal = this.getVal(newVal,dec10Val);
return Number(((thisIntVal) - (newIntVal))/dec10Val);
}
Number.prototype.div = function(newVal) {
newVal = Number(newVal)
var dec10Val = this.getDec10Val(this, newVal);
var thisIntVal = this.getVal(this, dec10Val);
var newIntVal = this.getVal(newVal,dec10Val);
return Number(((thisIntVal) / (newIntVal)));
}
Number.prototype.mul = function(newVal) {
newVal = Number(newVal)
var dec10Val = this.getDec10Val(this, newVal);
var thisIntVal = this.getVal(this, dec10Val);
var newIntVal = this.getVal(newVal,dec10Val);
return Number((thisIntVal * newIntVal)/Math.pow(dec10Val,2));
}
usage:
(0.1).add(0.3)

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