#Python中这个非常简短的代码试图模拟Eratosthenes" Sieve of Eratosthenes"对于具有(0)脚本短度约束的前N个自然数; (1)最小化“if”陈述'和' for / while循环&#39 ;; (2)CPU时间效率。
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上,它返回第一个中的素数:
有人愿意在上述限制条件下分享更有效的CPU时间代码吗?
答案 0 :(得分:6)
Eratosthenes的实际 NumPy筛子看起来像这样:
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)
它维护一个"可能是素数"标志并直接取消对应于质数倍数的标志,而不需要测试可除性,特别是对于当前正在处理的素数不能被整除的数字。
你正在做的是试验分工,你只需要通过考验是否可以被候选除数整除。即使是试验部门的良好实施也需要做更多的操作,而且比筛子更昂贵的操作。你的实现确实比这更有用,因为它考虑了非素数候选除数,并且因为它不断对数字进行可分性测试,它应该已经知道它是素数。
答案 1 :(得分:1)
1.94秒,持续10.000.000
def sieve_eratosthene(limit):
primes = [True] * (limit+1)
iter = 0
while iter < limit**0.5 :
if iter < 2:
primes[iter]= False
elif primes[iter]:
for i in range(iter*2, limit+1, iter):
primes[i] = False
iter+=1
return(x for x in range(number+1) if primes[x])
答案 2 :(得分:1)
这是使用NumPy执行此操作的简单方法。它有点类似于OP的索引编制思想,而不是在主循环内再次循环编制,但没有除法检查,只能进行切片。
它也类似于user2357112支持Monica的答案,但是这个仅考虑奇数,这使得它更快。
这是典型的仅奇数筛子:https://stackoverflow.com/a/20248491/8094047。
最后,我们有一个布尔数组,可以用来检查n以下的数字是否为质数(偶数除外,您可以使用&1或大约1来检查它们是否不包含数组)
平均n = 20000000的时间:0.1063s
import numpy as np
n = 20000000
isprime = np.ones(n, dtype=np.bool)
# odd only sieve
i = 3
while (i * i < n):
if isprime[i]:
isprime[i * i:n:2 * i] = False
i += 2
# test
print(isprime[97]) # should be True
答案 3 :(得分:1)
我决定玩这个游戏,并创建了一个进一步优化的NumPy版本,该版本由 @ user2357112支持Monica 发布,该版本使用Numba JIT加快了工作进度。
import numba
import numpy
import timeit
import datetime
@numba.jit(nopython = True, parallel = True, fastmath = True, forceobj = False)
def sieve (n: int) -> numpy.ndarray:
primes = numpy.full(n, True)
primes[0], primes[1] = False, False
for i in numba.prange(2, int(numpy.sqrt(n) + 1)):
if primes[i]:
primes[i*i::i] = False
return numpy.flatnonzero(primes)
if __name__ == "__main__":
timestart = timeit.default_timer()
print(sieve(1000000000))
timestop = timeit.default_timer()
timedelta = (timestop - timestart)
print(f"Time Elapsed: {datetime.timedelta(seconds = timedelta)}")
else:
pass
在笔记本电脑上,我在1e9
秒内筛选出了前十亿(0:00:10.378686
)个自然数中的质数。 JIT在这里至少提供了一个数量级的性能;在撰写本文时,下一个最快的答案花了0:01:27.059963
分钟。可悲的是,我在该系统(Mac)上没有Nvidia GPU和Cuda,否则我会使用它。