Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么我的埃拉托什筛这么慢?_Python_Performance_Algorithm_Time Complexity_Primes - Fatal编程技术网

Python 为什么我的埃拉托什筛这么慢?

Python 为什么我的埃拉托什筛这么慢?,python,performance,algorithm,time-complexity,primes,Python,Performance,Algorithm,Time Complexity,Primes,我正在解决欧拉项目的一些问题,为了解决一个问题,我不得不生成200万个素数。我对埃拉托什尼筛的实现非常缓慢,但我不知道为什么。有人能解释一下这个实现的主要问题吗。我觉得它很漂亮,然后我发现它非常糟糕:(.我在网上找到了另一个实现,它比我的要快得多 def generatePrimes(upperBound): numbers = range(2,upperBound+1) primes = [] while numbers: prime = number

我正在解决欧拉项目的一些问题,为了解决一个问题,我不得不生成200万个素数。我对埃拉托什尼筛的实现非常缓慢,但我不知道为什么。有人能解释一下这个实现的主要问题吗。我觉得它很漂亮,然后我发现它非常糟糕:(.我在网上找到了另一个实现,它比我的要快得多

def generatePrimes(upperBound):
    numbers = range(2,upperBound+1)
    primes = []

    while numbers:
        prime = numbers[0]
        primes.append(prime)
        numbers = filter((lambda x: x%prime),numbers)
    return primes
编辑:感谢所有的答案!结论是过滤器才是问题所在,因为它会遍历每个元素(而不仅仅是那些被标记为非素数的元素),而且每次都会创建一个新列表。使用良好的旧for循环和一轮过滤重写它,它的工作速度会快得多。新代码:

def generatePrimes(upperBound):
numbers = range(2,upperBound+1)

for i in xrange(len(numbers)):
    if(numbers[i] != 0):
        for j in xrange(i+numbers[i],len(numbers),numbers[i]):
            numbers[j] = 0

primes = filter(lambda x: x,numbers)
return primes

运行cProfile显示大部分时间都花在了过滤器上。用列表替换过滤器可以将速度提高大约2倍

numbers = [n for n in numbers if n%prime != 0]
但这并不能真正解决主要问题,即每次迭代都要重新创建数字列表,而且速度很慢
通过用0或类似物替换非素数来标记非素数。

埃拉托斯烯的筛子如下所示:

def sieve(n):
    primality_flags = [True]*(n+1)
    primality_flags[0] = primality_flags[1] = False
    primes = []
    for i, flag in enumerate(primality_flags):
        if flag:
            primes.append(i)
            for j in xrange(2*i, n+1, i):
                primality_flags[i] = False
    return primes
当外循环到达时,它对每个数进行一次处理,对每一个除以它的素数进行一次处理。大约1/2的数可被2整除,大约1/3可被3整除,依此类推;渐进地说,每个数被处理的平均次数是1+素数的倒数之和到n,因此筛具有渐近时间复杂度
O(n*log(log(n)))
,假设算法是常数时间。这非常好


你的函数不会这样做。你的
过滤器
会检查
数字
中的每个元素,不管它是否可以被
素数
整除。每个元素都会被处理每个素数,直到第一个素数将其整除为止,处理素数p会删除
数字
中约1/p的元素。让素数序列为p[0]、p[1]、p[2]等,并且让
数的大小序列为n[0]、n[1]、n[2]等,我们有以下近似递归:

n[0] = upperBound - 1
n[1] = n[0] * (p[0]-1)/p[0]
n[2] = n[1] * (p[1]-1)/p[1]
...
n[k+1] = n[k] * (p[k]-1)/p[k]

你的算法所需的时间大致与
n
值之和成正比,直到
numbers
为空。我还没有分析该序列的行为,但计算表明增长比
O(n*log(log(n)))
(编辑:我在撰写此答案时没有想到的一个答案是O((n/log(n))^2))

这是python2还是python3?首先,它不是Eratosthenes的筛子。它是。我认为从技术上讲,这是一个筛子,但你在每次迭代中都使用过滤函数执行大的分配。大多数筛子都经过优化,只执行一个大数组分配,而你的筛子从len开始执行大小为O(n)的分配(上限)@dustyrockpyle:不,这和Eratosthenes的筛子有很大区别。当外环到达时,SoE对每个数字处理一次,在其素因子分解中对每个素数处理一次;这个函数对每个素数处理一次,直到其第一个素因子。结果是,它对每个数字都处理了很多次平均e次。一件有帮助的事情是,一旦你测试的素数大于sqrt(上界),就打破循环,因为剩下的任何东西都保证是素数。你可以使用
yield i
来避免考虑
素数的时间复杂度。append(i)
@J.F.Sebastian:据我所知,这不会有什么帮助。
收益率
追加
具有相同的摊销时间复杂度。有人说:“理论上理论和实践没有区别。实践中有。”这都是平方根。如果你分析你的进度,求和;对于这两种情况,计算到上限
m
sqrt(m)
;它们是:对于m<1K…100K:m^1.64…1.80;对于m<1K…100K…1mln:m^1.17…1.27…1.34。如果你在代码中看到
n%prime
,这不是对埃拉托什尼的筛选。同意。生成复合物比测试它们更快(引用维基百科)@JamesK是的,因为您仅从其素数因子(低于其sqrt)生成每个组合,但在测试时,每个候选项都由所有素数(低于其sqrt)测试,而不仅仅是由其素数因子测试。