快速斐波纳契减速到超过1,000,000的爬行

时间:2013-10-31 03:23:38

标签: python performance algorithm recursion fibonacci

我通过快速加倍使用从矩阵取幂算法得到的算法编写了一个非常标准的斐波纳契函数,该算法应该在O(log(n))时间和调用中运行,但是在大约1,000,000的时候停止 - 即使这样应该只有大约25个电话。

代码:

"""
O(log(n)) time fibonacci algorithm using fast doubling derived from the matrix
squaring algorithm for the same thing.
"""

def fibonacci(num):
    "O(log(n)) implementation of fibonacci using fast doubling."
    if num >= 0:
        return fib_helper(num)[0]

def fib_helper(num):
    "Helper function for fibonacci()."
    if num == 0:
        return (0, 1)
    elif num == 1:
        return (1, 1)
    else:
        f_k, f_k_1 = fib_helper(num // 2)
        f_k_even = f_k * (2 * f_k_1 - f_k)
        f_k_odd = f_k_1 * f_k_1 + f_k * f_k
        return (f_k_even, f_k_odd) if num % 2 == 0 else (f_k_odd, f_k_even +
                f_k_odd)

此代码仅生成对fib_helper的log(n)调用和对fibonacci的一次调用。对于大于1,000,000的数字,它只会停止并且不会返回。

我已经尝试实现一个基本的装饰器来计算函数调用,它告诉我它只运行32次调用2 ^ 32,但它仍然在最后停止。

为什么这会在大整数上停止减速?

2 个答案:

答案 0 :(得分:9)

尝试像这样运行代码

print "calculating fib(1000000)"
res = fib(1000000)
print "displaying the result..."
print res

问题是fib(1000000)是一个非常大的数字(> 10 200000 )。您的计算机可以非常快速地对这些数字进行操作,因为一切都是以二进制形式完成的。

当您尝试显示数字时,需要将其转换为基数10.这可能非常耗时!

转换为十六进制更容易。这些位只需要分为四个,所以

print hex(res)

将很快开始吐出东西

答案 1 :(得分:3)

仅仅是为了感兴趣,因为我的decimal评论显然是不可理解的; - ),这是代码:

import decimal
from decimal import Decimal as D
DO = D(0)
D1 = D(1)

def fibonacci(num):
    from math import log10
    if num >= 0:
        ndigits = int(log10(1.62) * num + 100)
        decimal.getcontext().prec = ndigits
        decimal.getcontext().Emax = ndigits
        return fib_helper(num)[0]

def fib_helper(num):
    if num == 0:
        return (D0, D1)
    elif num == 1:
        return (D1, D1)

并且fib_helper()的其余部分保持不变(请参阅原始消息)。在Python 3中,decimal在C中实现,计算时间与使用本机(二进制)整数相当。但 point 是输出转换为十进制字符串的时间:它不是一个巨大的瓶颈,而是运行时的一个微不足道的部分。

例如,fibonacci(100000000)(一亿)在此框中大约需要30秒,但在此之后:

>>> from time import clock as now # on this box, `clock()` is wall-clock time
>>> if 1:
...    t = now()
...    print(len(str(x)))
...    print(now()-t)
...
20898764
0.10466078789343337

所以十分之一秒生成20多万个十进制数字的字符串。对于10亿个参数,大约0.9秒产生208,987,640位十进制数字:十进制数字明显是线性的。

注意:decimal实际上是瞄准进行十进制浮点和定点计算。虽然它可以很好地用于高精度整数计算,但您必须提前指定您需要的位数和最大指数。它没有“无界限”模式。上面的代码使用fibonacci(n)大约等于1.618**n