在python中有大量因子

时间:2013-05-01 20:32:03

标签: python algorithm factorial

这是我对阶乘的方法:

def factorial(n):
    '''Returns factorial of n'''
    r = 1
    for i in range(1, n + 1):
        r *= i
    return r

我认为这很简单,但我想你可以提高效率,因为像100000这样的大数字需要很长时间。我的问题是,有吗? math.factorial()也不好,它花费的时间大致相同。

10 个答案:

答案 0 :(得分:23)

按顺序乘以数字

for i in range(1, n + 1):
    r *= i
return r

非常快速地创建一个大数字(如成千上万位),然后你有一个巨大的数字和一个小数字的很多乘法。其中至少有一个因素很大的乘法很慢。

通过减少涉及大数的乘法次数,可以大大加快速度,例如

def range_prod(lo,hi):
    if lo+1 < hi:
        mid = (hi+lo)//2
        return range_prod(lo,mid) * range_prod(mid+1,hi)
    if lo == hi:
        return lo
    return lo*hi

def treefactorial(n):
    if n < 2:
        return 1
    return range_prod(1,n)

生成,计算100000! % 100019的计时(我首先尝试len(str(fun(100000)),但转换为字符串的速度非常慢,因此差异看起来比它小):

$ python factorial.py 
81430
math.factorial took 4.06193709373 seconds
81430
factorial took 3.84716391563 seconds
81430
treefactorial took 0.344486951828 seconds

100000!加速超过10倍。

答案 1 :(得分:7)

如果您需要较短的执行时间并且不需要尽可能高的准确度,则可以使用近似公式,例如: Stirling approximation

答案 2 :(得分:5)

因子变得非常大,因此处理数字的对数通常会更好。

许多语言都有 lgamma 库函数,它可以计算n-1阶乘的自然对数。

这意味着您可以通过 lgamma(n + 1)计算阶乘(n)的自然对数。

您可以除以log10将其转换为10对数的基数。

因此,如果你只想要数字位数,那么这个Python代码将立即给出答案:

from math import *
print ceil(lgamma(100000+1)/log(10))

答案 3 :(得分:2)

如果你只是需要近似,Ramanujan的阶乘近似应该比斯特林更准确。

如果您需要(或想要)精确的东西,您可以尝试GMP,即GNU多精度库。我已经成功地使用它在Python中对大数字进行素性测试。

答案 4 :(得分:0)

你意识到阶乘(100000)是aproximately 2.8242294080×10 ^ 456,573
这就是为什么它很慢,这是巨大的。

答案 5 :(得分:0)

你可以返回伽玛函数(math.gamma(x)),但用for循环生成阶乘可能会更快

答案 6 :(得分:0)

由四元效应引起的减速:随着n越大,你必须做更多的乘法,但你也必须乘以更大的数字。

找到更好的算法并不容易。您可以尝试利用对称性(如在FFT中)。也可以用不同的顺序进行乘法,中间结果,这样你最终只会在最后只增加几个非常大的数字,但我还没想到最后。无论如何,您必须找到 law 才能利用。

here获取更多灵感。

答案 7 :(得分:0)

您可以使用reduce函数而不是显式循环:

>>> from functools import reduce
>>> mul = int.__mul__
>>> len(str(reduce(mul, range(2,100001), 1)))
456574
>>> 

在Python 2中,您需要使用long:long.__mul__len(str(reduce(mul, range(2L,100001L), 1L)))

答案 8 :(得分:0)

真正需要真阶乘值n实际上是不寻常的!在许多应用领域中。通常,使用阶乘的自然对数更现实。我想不出无法将日志用作更好的选择的任何应用程序,因为阶乘最常用于计算相关的值 选择事物组合的可能性。

要计算的常见事物是基于因子的概率,例如选择二项式系数(n k)= n! /(k!(n-k)!)。给定这是阶乘的比率,则log(n k)= log(n!)-log(k!)-log((n-k)!),可以使用各种对数阶乘近似之一可靠地计算出log(n k)= log(n!)-log(k!)-log((n-k)!)。而且,如果您进行大量概率数学运算,则通常无论如何最好还是在对数域中进行测量(以分贝为单位的测量概率),因为它经常涉及到范围极广的小于1的数字,因此使用common时,数学精度将很快崩溃。如果未使用日志版本,则为浮点表示形式。

ETJaynes是一位著名的数学家和概率论专家,因此我推荐他的书《概率论:科学的逻辑》作为该主题以及使用对数概率的贝叶斯推理和信息论的可读性很强的资料。 / p>

答案 9 :(得分:-1)

我做了 2,000,000! (2 百万)Chez Scheme 9.5.4 在 Lispide 中运行。计算需要 1 小时,在屏幕上打印需要 19 分钟。非常令人印象深刻。 弗朗切斯科