【问题标题】:Optimizing a Prime Number Factorization algorithm优化素数分解算法
【发布时间】:2014-04-03 04:29:15
【问题描述】:

下面是一个算法,它找到给定数字 N 的素数分解。我想知道是否有任何方法可以使用 HUGE 数字更快地实现这一点。我说的是20-35位数字。我想尝试让这些尽可能快地进行。有什么想法吗?

import time

def prime_factors(n):
    """Returns all the prime factors of a positive integer"""
    factors = []
    divisor = 2        
    while n > 1:        
        while n % divisor == 0:
            factors.append(divisor)
            n /= divisor          
        divisor = divisor + 1
        if divisor*divisor > n:
            if n > 1: 
                factors.append(n)
            break
    return factors

#HUGE NUMBERS GO IN HERE!
start_time = time.time()
my_factors = prime_factors(15227063669158801)
end_time = time.time()
print my_factors
print "It took ", end_time-start_time, " seconds."

【问题讨论】:

  • 以上号码你几点钟?
  • 不到一秒。但是对于一些20位及以上的数字,需要30多秒!
  • 不是每次将 divisor 递增 1,而是可以遍历素数。
  • @JacobKudria:大多数时候,附加到列表不需要调整大小。列表大小以这样一种方式缩放,即添加 N 个项目需要花费 O(N) 的总时间。预分配有时可以节省时间,但不多。

标签: python optimization factorization


【解决方案1】:

你的算法是试除法,它的时间复杂度为 O(sqrt(n))。您可以通过仅使用 2 和奇数作为试除数来改进您的算法,或者通过仅使用质数作为试除数更好,但时间复杂度将保持 O(sqrt(n))。

要跑得更快,您需要更好的算法。试试这个:

def factor(n, c):
    f = lambda(x): (x*x+c) % n
    t, h, d = 2, 2, 1
    while d == 1:
        t = f(t); h = f(f(h)); d = gcd(t-h, n)
    if d == n:
        return factor(n, c+1)
    return d

要拨打你的号码,说

print factor(15227063669158801, 1)

这几乎立即返回(可能是复合的)因子 2090327。它使用了一种称为rho算法的算法,由 John Pollard 在 1975 年发明。rho 算法的时间复杂度为 O(sqrt(sqrt(n))),因此比试除法要快得多。

还有许多其他的整数分解算法。对于您感兴趣的 20 到 35 位范围内的数字,椭圆曲线算法非常适合。它应该在不超过几秒钟内分解该大小的数字。另一种非常适合此类数字的算法,尤其是半素数(正好有两个素数因子)是 SQUFOF。

如果您对使用素数编程感兴趣,我在我的博客上谦虚地推荐this essay。完成此操作后,我博客上的其他条目将讨论椭圆曲线分解、SQUFOF 以及各种其他更强大的分解更大整数的方法。

【讨论】:

  • 素数上的 TD 是 ~ 2sqrt(n)/log(n) 我认为。
  • 我认为你是对的,但是在 n 的范围内,试除法是有意义的,log(n) 的因子并不重要,尤其是当你只得到它的一半时,因此,无论您如何实现它(赔率、2、3、5 轮、素数),都将试除法视为 O(sqrt(n)) 算法是有道理的。至少,我总是这样做。
  • 根据经验,我只得到那一半的一半,但 6.8 倍的加速仍然很明显 :)(素数与赔率的 TD 分解,扣除素数生成)。再增加 1 位,就是 7.2 倍。所以我认为它“比 sqrt(n) 略好”。 “好得多”意味着当然可以加速数千或数百万。这意味着我可以将 TD 用于大约两个数字,带质数。 - (另外,我用质数尝试了你的代码...... :))
  • @WIllNess:(关于您的括号注释)如果您尝试考虑质数,那么您应该得到任何东西。
  • 但我没有被警告! :) :)
【解决方案2】:

例如,列出数字 100 的所有素数分解。

  • 检查 2 是否为分解之一。然后,可以删除 2
  • 检查 3 是否为分解之一。然后,可以删除 3
  • 4 已从可能的集合中移除。
  • 勾选5,然后将10、15、20、...、100去掉。
  • 6 已删除。
  • 检查7,.... ....

【讨论】:

    【解决方案3】:

    似乎没有检查除数。对不起,如果我错了,但你怎么知道除数是否是素数?您的除数变量在每次循环后增加 1,所以我假设它会生成很多合数。

    【讨论】:

      【解决方案4】:

      至少在一般情况下,对该算法的优化不会允许您分解 35 位数字。原因是最多 35 位的素数数量太高,无法在合理的时间内列出,更不用说尝试除以每个素数了。即使有人愿意尝试,存储它们所需的位数也会太多。在这种情况下,您需要从general purpose factorization algorithms 列表中选择不同的算法。

      但是,如果所有素数都足够小(比如低于 10^12 左右),那么你可以使用分段的Sieve of Eratosthenes,或者简单地找到一个素数列表,直到某个实际数字(比如 10^12左右)在线并使用它而不是尝试计算素数并希望列表足够大。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-12
        • 2018-03-29
        • 2010-12-03
        • 2011-07-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-13
        相关资源
        最近更新 更多