Python 为什么是";“分而治之”;对大整数如此快速地计算阶乘的方法?

Python 为什么是";“分而治之”;对大整数如此快速地计算阶乘的方法?,python,factorial,divide-and-conquer,Python,Factorial,Divide And Conquer,我最近决定研究大整数的阶乘算法,这种“分而治之”算法比简单的迭代法和素数阶乘法更快: def multiply_range(n, m): print n, m if n == m: return n if m < n: return 1 else: return multiply_range(n, (n+m)/2) * multiply_range((n+m)/2+1, m) def factorial(n)

我最近决定研究大整数的阶乘算法,这种“分而治之”算法比简单的迭代法和素数阶乘法更快:

def multiply_range(n, m):
    print n, m
    if n == m:
        return n
    if m < n:
        return 1
    else:
        return multiply_range(n, (n+m)/2) * multiply_range((n+m)/2+1, m)

def factorial(n):
    return multiply_range(1, n)
def倍增_范围(n,m):
打印n,m
如果n==m:
返回n
如果m

我理解算法的工作原理,它只是递归地将乘法分解成更小的部分。我不明白的是为什么这种方法更快。

简单的回答是你错了。它不是很快:

In [34]: %timeit factorial(100)
10000 loops, best of 3: 57.6 us per loop

In [35]: %timeit reduce(operator.mul, range(1, 101))
100000 loops, best of 3: 19.9 us per loop
换言之,它的速度大约是直截了当的单线客机的三倍


对于较小的
n
值,差异更为显著。

与@NPE的答案相反,您的方法更快,仅适用于非常大的数字。 对我来说,我开始看到分而治之的方法在输入~10^4时变得更快。在10^6及以上时,传统循环的失败率是无法与之相比的

我不是硬件乘法器方面的专家,我希望有人能对此进行扩展,但我的理解是,乘法是以数字对数字的方式进行的,就像我们在小学教的那样

传统的阶乘循环将从较小的数字开始,结果将不断增长。最后,你会用一个相对较小的数字来计算一个巨大的数字,这是一个昂贵的计算,因为数字不匹配

比较

reduce(operator.mul, range(1,10**5))
reduce(operator.mul, range(10**5,1,-1))
第二种是较慢的,因为结果增长较快,导致更快地进行更昂贵的计算


对于大数,您的方法比这两种方法都快几个数量级,因为它将阶乘分解为大小相似的部分。子结果具有相似的位数,并且乘法速度更快

我不认为它比带传统for循环的阶乘更快。你测量过了吗?对于非常大的数字来说,速度更快。如果您迭代地执行此操作,您将乘以越来越大的数字,这将变得越来越慢。如果你能减少数字的大小,比如说,把它们分成两半(递归),计算速度会逐渐加快。但是更大的开销意味着这只适用于超过某个阈值的大小。尝试更大的输入,分而治之是针对大的因数。这一观察是正确的。然而,值得指出的是,它是基于一些非常不现实的假设,即任何人都希望计算阶乘:(1)迭代(而不是分析);(2) 确切地说;(3)使用整数数学,对10**5的输入进行计算。我认为OP做出了这些假设,第二,通常在10^(10^x)左右,你可以切换到斯特林近似