改善我对Eratosthenes筛子的实施

时间:2020-04-15 13:22:07

标签: python performance primes

我正在创建Eratosthenes筛子,以便更有效地求和1到大数n之间的素数。我想要做的是创建一个从2到n的列表,然后删除2的倍数,然后删除3的倍数,再删除列表中下一个数字的倍数,依此类推。我创建的代码在时间上性能很慢,几乎就像通过检查每个条目是否为质数来创建列表一样。我想我要进行的操作数是有序的: n的平方根(第一个while循环)乘以n的平方根(小于第二个while循环)。因此,我不确定remove方法或其他方法是否会降低它的速度。

我的代码是这个:

window.onmessage = selection => {
   let message = selection.data.pluginMessage;
   console.log(message);
}

1 个答案:

答案 0 :(得分:3)

假设

问题在于如何缩短软件的运行时间,因为它非常慢。

执行以下两次代码更改以加快代码速度

  1. 而不是保留素数列表,而是将数字检查为素数(真) 或非主要(错误)
  2. 仅检查大于2的奇数

代码

def sieve_of_Eratosthenes2(n):
    if n < 2:
        return []
    if n < 3:
        return [2]

    L = [True] * (n+1)    # all numbers set as primes initially

    # modifies prime flag in list for odd numbers
    for i in range(3, n, 2): # Check odd numbers for prime (no need to check even numbers)
        if L[i]: # A prime
            L[i*i::i] = [False]*len(L[i*i::i]) # from i^2 in increments of i

    # Report prime 2 + odd primes
    return [2] + [i for i in range(3, n, 2) if L[i]]  # Get odd numbers whose flag is 
                                                      # still True

新代码

%timeit sieve_of_Eratosthenes2(1000)
188 µs ± 16.6 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit sieve_of_Eratosthenes2(100000)
16 ms ± 1.58 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In going from 1, 000 to 100, 000 time 
(i.e. 100X), time increased by ~85, 
so almost linear

旧代码

 %timeit sieve_of_Eratosthenes(1000)
 25.2 ms ± 1.59 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
 sieve_of_Eratosthenes2(100000)
 261.45 seconds  (using time module)

In going from 1, 000 to 100, 000 (100X)
time increased by factor of ~10, 000
So quadratic increase in time (i.e. 100^2).

说明

Sieve of Eratosthenes的复杂度是

O(N log (log N))

这几乎是线性的,因为操作通常是O(1)来将数组中的数字标记为True(素数)和False(非素数)。

在原始算法编号中,非质数被删除而不是标记为:

O(N) per removal.

这给Eratosthenes筛网的复杂度增加了N的额外因素,导致原始算法的复杂度为:

O(N*N*log (log N))

因此,运行时间已确认为二次方。