不同素因子函数的速度

时间:2016-05-05 16:59:37

标签: python performance list-comprehension prime-factoring

我有这三个素因子函数,我不明白它们的时间复杂性的差异。

这是我开始时的第一个功能,希望更快。我已经有了一个非常快速的素数功能,但我认为Sieve会更快。

def is_prime(i):
    if i <= 1: return False
    if i <= 3: return True
    if i%3 == 0 or i%2 == 0: return False
    return sum((1 for y in xrange(5, int(i**0.5)+1, 6) if i%y == 0 or i%(y+2) == 0)) == 0

prime_factors_1 = lambda x: [i for i in range(1,x) if x%i == 0 and is_prime(i)]

这是我在这个家伙博客上发现的Eratosthenes Sieve的实施:http://www.drmaciver.com/2012/08/sieving-out-prime-factorizations/

def prime_factorizations(n):
   sieve = [[] for x in xrange(0, n+1)]
   for i in xrange(2, n+1):
      if not sieve[i]:
         q = i
         while q < n:
             for r in xrange(q, n+1, q):
                 sieve[r].append(i)
             q *= i
   return sieve[-1]

我喜欢尝试改进我发现的示例,我喜欢尝试减少行数,同时保留功能和时间/空间效率。我可能已经对这个列表理解过度了。

def prime_factors_2(n):
    factors = [[] for n in xrange(0,n+1)]
    [[[factors[r].append(i) for r in xrange(q, n+1, q)] for q in range(i,n,i)] for i in (y for y in xrange(2,n+1) if not factors[y])]   
    return factors[-1]

我定时并得到了这个输出:

prime_factorizations: 1.11333088677
prime_factors_1:      0.0737618142745
prime_factors_2:     10.7310789671

有些事情我不明白这些时间:

  1. 为什么非筛子最快?
    • 是因为它只会产生明显的素因子吗?
  2. 为什么列表理解的筛子要慢得多?
    • (分层)列表理解本身是否较慢?
  3. 什么算法会比我原来的非筛子更快?

1 个答案:

答案 0 :(得分:2)

  

为什么非筛子最快?

其他功能可以产生大量的工作来产生您不关心的数字因素。

  

为什么列表理解的筛子这么慢?

因为你搞砸了。这部分:

[[[factors[r].append(i) for r in xrange(q, n+1, q)] for q in range(i,n,i)] for i in (y for y in xrange(2,n+1) if not factors[y])]
#                                                   ^^^^^^^^^^^^^^^^^^^^^

不等同于原始代码中的while循环,它将q乘以i而不是添加i。即使你已经把它弄好了,但是使用列表理解副作用会让人感到困惑,这与列表推导的目的相反,并且浪费了你构建的Nones巨大嵌套列表的空间。

  

什么算法会比我原来的非筛子更快?

您可以将您找到的素数因子分开,从而无需检查以后的素数因素,并减少您需要检查的因素数量:

def prime_factors(n):
    factors = []
    if n % 2 == 0:
        factors.append(2)
        while n % 2 == 0:
            n //= 2
    candidate = 3
    while candidate * candidate <= n:
        if n % candidate == 0:
            factors.append(candidate)
            while n % candidate == 0:
                n //= candidate
        candidate += 2
    if n != 1:
        factors.append(n)
    return factors