diff --git a/seriously/SeriouslyCommands.py b/seriously/SeriouslyCommands.py index 01d0167..3b237cb 100755 --- a/seriously/SeriouslyCommands.py +++ b/seriously/SeriouslyCommands.py @@ -37,6 +37,11 @@ phi = (1+5**.5)/2 +@memoize +def Lucas(n): + [a,b] = fast_fib(n) + return (a<<1)+b + fib_cache = {0:0, 1:1, 2:1} def Fib(n): @@ -44,11 +49,36 @@ def Fib(n): if n in fib_cache: return fib_cache[n] else: - largest = max(fib_cache) - while largest < n: - fib_cache[largest+1] = Fib(largest) + Fib(largest-1) - largest += 1 - return fib_cache[n] + result = fast_fib(n)[1] + fib_cache[n] = result + return result + +# F(2n) = (F(n-1) + F(n+1)) * F(n) +# = (F(n-1) + F(n-1) + F(n)) * F(n) +# = (2F(n-1) + F(n)) * F(n) + +# F(2n-1) = F(n-1)*F(n-1) + F(n)*F(n) + +# this returns [F(n-1), F(n)], so +# the implementation should be +# fast_fib(1000)[1] +def fast_fib(n): + global fib_cache + if n==0: return [1,0] + shift = n>>1 + if shift in fib_cache and shift-1 in fib_cache: + [a,b] = [fib_cache[shift-1],fib_cache[shift]] + else: + [a,b] = fast_fib(shift) + fib_cache[shift-1] = a + fib_cache[shift] = b + b2 = b*b + a,b = a*a+b2, (a<<1)*b+b2 + if n%2 == 1: + fib_cache[n-1] = b + return [b,a+b] + fib_cache[n-1] = a + return [a,b] def prod(iter): return reduce(operator.mul, iter, 1)