Python 不同素因子函数的速度

Python 不同素因子函数的速度,python,performance,list-comprehension,prime-factoring,Python,Performance,List Comprehension,Prime Factoring,我有这3个素因子函数,我不理解它们在时间复杂度上的差异 这是我开始使用的第一个函数,我想让它更快。我已经有了一个相当快的素数函数,但我认为筛子会更快 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)

我有这3个素因子函数,我不理解它们在时间复杂度上的差异

这是我开始使用的第一个函数,我想让它更快。我已经有了一个相当快的素数函数,但我认为筛子会更快

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)]
我计时并得到以下输出:

prime_factorizations: 1.11333088677
prime_factors_1:      0.0737618142745
prime_factors_2:     10.7310789671
关于这段时间,有几件事我不明白:

  • 为什么非筛网最快?
    • 是因为它只产生不同的主要因素吗
  • 为什么列表理解的筛子要慢得多?
    • (分层)列表理解是否天生较慢
  • 什么算法会比我原来的非筛选算法更快
  • 为什么非筛网最快

    其他函数做了大量工作来生成您不关心的数字因子

    为什么列表理解的筛子要慢得多

    因为你搞砸了。本部分:

    [[[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
    。即使你做对了,使用列表理解的副作用也会让人困惑,这与列表理解的目的背道而驰,而且对于你构建的庞大的嵌套非列表来说浪费了空间

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

    您可以将发现的素数因子划分出来,以避免检查后面的素数因子,并减少需要检查的因子数:

    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
    
    def基本因子(n):
    因子=[]
    如果n%2==0:
    因素。附加(2)
    当n%2==0时:
    n/=2
    候选人=3
    当候选人*候选人
    为什么非筛网最快

    其他函数做了大量工作来生成您不关心的数字因子

    为什么列表理解的筛子要慢得多

    因为你搞砸了。本部分:

    [[[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
    。即使你做对了,使用列表理解的副作用也会让人困惑,这与列表理解的目的背道而驰,而且对于你构建的庞大的嵌套非列表来说浪费了空间

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

    您可以将发现的素数因子划分出来,以避免检查后面的素数因子,并减少需要检查的因子数:

    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
    
    def基本因子(n):
    因子=[]
    如果n%2==0:
    因素。附加(2)
    当n%2==0时:
    n/=2
    候选人=3
    
    而候选者*候选者这个问题可能有一些你想要的答案:。您还可以使用
    dis.dis
    调查每个函数中实际发生的情况,以确定其中一个函数较重的原因。您是如何计时的?对于小数字,我希望更直接的方法更快。@g.d.d.c谢谢!那看起来很有趣useful@TadhgMcDonald Jensen I使用timeit输入1234567如果您发现自己在列表理解中使用
    append
    或其他变异操作,或者忽略返回值,请停止。你在无缘无故地建立一个巨大的额外列表,并使用一个看起来没有变异的结构来产生副作用。你应该使用循环。这个问题可能有你想要的一些答案:。您还可以使用
    dis.dis
    调查每个函数中实际发生的情况,以确定其中一个函数较重的原因。您是如何计时的?对于小数字,我希望更直接的方法更快。@g.d.d.c谢谢!那看起来很有趣useful@TadhgMcDonald Jensen I使用timeit输入1234567如果您发现自己在列表理解中使用
    append
    或其他变异操作,或者忽略返回值,请停止。你在无缘无故地建立一个巨大的额外列表,并使用一个看起来没有变异的结构来产生副作用。你应该使用一个循环。