Fast Fibonacci computation

前端 未结 4 1798
失恋的感觉
失恋的感觉 2021-02-04 17:56

I saw a comment on Google+ a few weeks ago in which someone demonstrated a straight-forward computation of Fibonacci numbers which was not based on recursion and didn\'t use mem

相关标签:
4条回答
  • 2021-02-04 18:29

    Since Fibonacci sequence is a linear recurrence, its members can be evaluated in closed form. This involves computing a power, which can be done in O(logn) similarly to the matrix-multiplication solution, but the constant overhead should be lower. That's the fastest algorithm I know.

    EDIT

    Sorry, I missed the "exact" part. Another exact O(log(n)) alternative for the matrix-multiplication can be calculated as follows

    from functools import lru_cache
    
    @lru_cache(None)
    def fib(n):
        if n in (0, 1):
            return 1
        if n & 1:  # if n is odd, it's faster than checking with modulo
            return fib((n+1)//2 - 1) * (2*fib((n+1)//2) - fib((n+1)//2 - 1))
        a, b = fib(n//2 - 1), fib(n//2)
        return a**2 + b**2
    

    This is based on the derivation from a note by Prof. Edsger Dijkstra. The solution exploits the fact that to calculate both F(2N) and F(2N-1) you only need to know F(N) and F(N-1). Nevertheless, you are still dealing with long-number arithmetics, though the overhead should be smaller than that of the matrix-based solution. In Python you'd better rewrite this in imperative style due to the slow memoization and recursion, though I wrote it this way for the clarity of the functional formulation.

    0 讨论(0)
  • 2021-02-04 18:36

    Using the weird square rooty equation in the other answer closed form fibo you CAN compute the kth fibonacci number exactly. This is because the $\sqrt(5)$ falls out in the end. You just have to arrange your multiplication to keep track of it in the meantime.

    def rootiply(a1,b1,a2,b2,c):
        ''' multipy a1+b1*sqrt(c) and a2+b2*sqrt(c)... return a,b'''
        return a1*a2 + b1*b2*c, a1*b2 + a2*b1
    
    def rootipower(a,b,c,n):
        ''' raise a + b * sqrt(c) to the nth power... returns the new a,b and c of the result in the same format'''
        ar,br = 1,0
        while n != 0:
            if n%2:
                ar,br = rootiply(ar,br,a,b,c)
            a,b = rootiply(a,b,a,b,c)
            n /= 2
        return ar,br
    
    def fib(k):
        ''' the kth fibonacci number'''
        a1,b1 = rootipower(1,1,5,k)
        a2,b2 = rootipower(1,-1,5,k)
        a = a1-a2
        b = b1-b2
        a,b = rootiply(0,1,a,b,5)
        # b should be 0!
        assert b == 0
        return a/2**k/5
    
    if __name__ == "__main__":
        assert rootipower(1,2,3,3) == (37,30) # 1+2sqrt(3) **3 => 13 + 4sqrt(3) => 39 + 30sqrt(3)
        assert fib(10)==55
    
    0 讨论(0)
  • 2021-02-04 18:54

    This is too long for a comment, so I'll leave an answer.

    The answer by Aaron is correct, and I've upvoted it, as should you. I will provide the same answer, and explain why it is not only correct, but the best answer posted so far. The formula we're discussing is:

    Computing Φ is O(M(n)), where M(n) is the complexity of multiplication (currently a little over linearithmic) and n is the number of bits.

    Then there's a power function, which can be expressed as a log (O(M(n)•log(n)), a multiply (O(M(n))), and an exp (O(M(n)•log(n)).

    Then there's a square root (O(M(n))), a division (O(M(n))), and a final round (O(n)).

    This makes this answer something like O(n•log^2(n)•log(log(n))) for n bits.


    I haven't thoroughly analyzed the division algorithm, but if I'm reading this right, each bit might need a recursion (you need to divide the number log(2^n)=n times) and each recursion needs a multiply. Therefore it can't be better than O(M(n)•n), and that's exponentially worse.

    0 讨论(0)
  • 2021-02-04 18:54

    From Wikipedia,

    For all n ≥ 0, the number Fn is the closest integer to phi^n/sqrt(5) where phi is the golden ratio. Therefore, it can be found by rounding, that is by the use of the nearest integer function

    0 讨论(0)
提交回复
热议问题