JavaScriptでメモ化関数(つづき)
前回5/6に紹介したメモ化関数についてちょっと補足。
メモ化した関数を別の名前にしてしまうと、下記のような再帰的な関数fibはそれ自体は高速化されない。2回目以降に同じ引数をもつときだけ高速化されるに過ぎない。
function fib(n) { return (n < 2) ? n : fib(n - 1) + fib(n - 2); } var fib2 = memoize(fib, null); var v = fib2(100); // ほぼ永久に計算が終わらない。
再帰の途中結果もメモ化すれば高速化されるので、メモ化関数を別名にせず、単純に同じ名前にすればよい。
var fib_org = fib; fib = memoize(fib_org, null); var v = fib(100); // v=354224848179262000000 が一瞬で計算される。
ここで、memoize()関数は以下のもの:
// memoize: a general-purpose function to enable a function to use memoization // func: the function to be memoized // context: the context for the memoized function to execute within // Note: the function must use explicit, primitive parameters (or objects // that generate unique strings in a toString() method) function memoize (func, context) { function memoizeArg (argPos) { var cache = {}; return function () { if (argPos == 0) { if (!(arguments[argPos] in cache)) { cache[arguments[argPos]] = func.apply(context, arguments); } return cache[arguments[argPos]]; } else { if (!(arguments[argPos] in cache)) { cache[arguments[argPos]] = memoizeArg(argPos - 1); } return cache[arguments[argPos]].apply(this, arguments); } } } // JScript doesn't grok the arity property, but uses length instead var arity = func.arity || func.length; return memoizeArg(arity - 1); }