122
Behold, the memoizer, which takes any single-argument function and memoizes it. Turns out to be marginally faster than @xPheRe's solution, including the limit on the size of the cache and associated checking, because I use shortcircuiting and so on.
function memoize(func, max) {
max = max || 5000;
return (function() {
var cache = {};
var remaining = max;
function fn(n) {
return (cache[n] || (remaining-- >0 ? (cache[n]=func(n)) : func(n)));
}
return fn;
}());
}
function fact(n) {
return n<2 ? 1: n*fact(n-1);
}
// construct memoized version
var memfact = memoize(fact,170);
// xPheRe's solution
var factorial = (function() {
var cache = {},
fn = function(n) {
if (n === 0) {
return 1;
} else if (cache[n]) {
return cache[n];
}
return cache[n] = n * fn(n -1);
};
return fn;
}());
Approximately 25x faster on my machine in Chrome than the recursive version, and 10% faster than xPheRe's.
Just for completeness, here is a recursive version that would allow tail call optimization. I'm not sure if tail call optimizations are performed in JavaScript though..
function rFact(n, acc)
{
if (n == 0 || n == 1) return acc;
else return rFact(n-1, acc*n);
}
To call it:
rFact(x, 1);
Here is an implementation which calculates both positive and negative factorials. It's fast and simple.
var factorial = function(n) {
return n > 1
? n * factorial(n - 1)
: n < 0
? n * factorial(n + 1)
: 1;
}