关于numpy:Python中的Eratosthenes高效筛

An Efficient Sieve of Eratosthenes in Python

#Python中的这段非常短而简单的代码尝试针对前N个自然数模拟" Eratosthenes筛",其约束为(0)脚本简短; (1)最小化" if语句"和" for / while循环"; (2)就CPU时间而言的效率。

1
2
3
4
5
6
7
import numpy as np
N = 10**5
a = np.array(range(3,N,2))
for j in range(0, int(round(np.sqrt(N),0))):
    a[(a!=a[j]) & (a%a[j] == 0)] = 0
    a = a[a!=0]
a = [2]+list(a)

在Intel Core I5上,它返回第一个中的质数:

  • N = 100,000在0.03秒内;
  • N = 1,000,000在0.63秒内;
  • N = 2,000,000秒内10,000,000。

在上述限制内,有人愿意在CPU时间方面共享更有效的代码吗?


实际的Eratosthenes NumPy筛子如下所示:

1
2
3
4
5
6
7
8
9
def sieve(n):
    flags = numpy.ones(n, dtype=bool)
    flags[0] = flags[1] = False
    for i in range(2, n):
        # We could use a lower upper bound for this loop, but I don't want to bother with
        # getting the rounding right on the sqrt handling.
        if flags[i]:
            flags[i*i::i] = False
    return numpy.flatnonzero(flags)

它维护"可能为素数"标志的数组,并直接取消设置与素数倍数相对应的标志,而无需测试可除性,尤其是对于不能被当前正被素数整除的数字。

您正在做的是试算除法,即您只需要测试一下数字是否可被候选除数整除。 即便是良好的试验划分实施,也需要比筛分更多的操作和更昂贵的操作。 您的实现所要做的工作甚至更多,这是因为它考虑了非素数候选除数,并且因为它一直在对其本应知道是质数的数字执行除数测试。