繁体   English   中英

python中大数的因数

[英]Factorial of a large number in python

这是我对阶乘的方法:

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

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

依次将数字相乘,

r = 1
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的计算100000! % 100019 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 倍100000! .

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

许多语言都有一个lgamma库函数,用于计算 n-1 阶乘的自然对数。

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

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

所以如果你只想要数字的数量,那么这个 Python 代码会立即给出答案:

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

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

如果您只需要一个近似值,那么 Ramanujan 的阶乘近似应该比 Stirling 的更准确。

如果您需要(或想要)精确的东西,您可以尝试 GMP,即 GNU Multiple Precision 库。 我已经成功地将它用于 Python 中大量数字的素性测试。

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

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

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

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

一个常见的计算是基于阶乘的概率,例如选择二项式系数 (nk) = n! /(k!(nk)!)。 鉴于这是阶乘的比率,那么 log(nk) = log(n!)-log(k!)-log((nk)!) 使用各种对数阶乘近似值之一可靠地计算。 如果你做了很多概率数学,通常最好还是在对数域中进行(以分贝为单位测量概率),因为它通常涉及非常广泛的小于 1 的数字范围,因此使用 common 数学精度会很快崩溃如果未使用日志版本,则为浮点表示。

ETJaynes 是一位著名的数学家和概率论专家,我推荐他的书“概率论:科学的逻辑”作为这个主题和贝叶斯推理和使用对数概率的信息论的非常易读的来源。

你知道那阶乘(100000)是aproximately 2.8242294080×10 ^ 456573
这就是为什么它很慢,它很大。

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

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

找到更好的算法并不容易。 您可以尝试利用对称性(如在 FFT 中)。 以不同的顺序进行乘法也是很值得的,得到中间结果,这样你最终只会乘以几个非常大的数字,但我一直没有想到这一点。 在任何情况下,您都必须找到可以利用的法律

在这里寻找更多灵感。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM