本文所利用的素数性质是:所有的素数都是奇数,且除2,3外其余素数都出现在6n-1与6n+1这两个数列中
具体代码如下
首先创建一个长度为n的false列表,再将索引为2,3,和6n+1、6n-1这两个数列在列表中的值改为True
L = [False]*N
L[2]=L[3]=True
L[5:N:6] = [True]*len(L[5:N:6])#数列6n-1
L[7:N:6] = [True]*len(L[7:N:6])#数列6n+1
这两数列中除了包含素数外还有一些非素数,所以我们需要想办法将那些非素数对应的值改为false
6n-1 : 5 11 17 23 29 35 41 47 53 59……
6n+1: 7 13 19 25 31 37 43 49 55 61……
不难发现这些数字都是前面那些素数的倍数,所以可以建立循环删除倍数
for i in range(5,int(N**0.5)+1,6):
if L[i]:
L[i*i:N:2*i] = [False]*len(L[i*i:N:2*i])#删除倍数
for i in range(7,int(N**0.5)+1,6):
if L[i]:
L[i*i:N:2*i] = [False]*len(L[i*i:N:2*i])#删除倍数
删除倍数这里 L[ii:N:2i],从i的i倍开始,而不是从i的1倍开始,原因是i的j倍(j<i)已经在前面删除过了,如果再删除就会重复工作;间隔为2*i的原因是,因为6n+1与6n-1这两个数列中只存在i的奇数倍,所以我们只需要删除i的奇数倍就好。
进行完上述工作,我们的列表L就成功记录到了N以内所有的素数,我们只需要利用一个循环将值为TRUE的索引读出来就好了
primes = []
for i in range(N):
if L[i]:primes.append(i)
下面是整个代码
#!/bin/env python
#-*-coding:utf-8-*-
import time
def prime(N):
L = [False]*N
primes = []
L[2]=L[3]=True
L[5:N:6] = [True]*len(L[5:N:6])#数列6n-1
L[7:N:6] = [True]*len(L[7:N:6])#数列6n+1
for i in range(5,int(N**0.5)+1,6):
if L[i]:
L[i*i:N:2*i] = [False]*len(L[i*i:N:2*i])#删除倍数
for i in range(7,int(N**0.5)+1,6):
if L[i]:
L[i*i:N:2*i] = [False]*len(L[i*i:N:2*i])#删除倍数
for i in range(N):
if L[i]:primes.append(i)
return primes
if __name__=='__main__':
t0=time.time()
N = 10000001
primes = prime(N)
#print(primes)
print('共找出%d个素数'%len(primes))
runtime=time.time()-t0
print('运行时间为',runtime, sep='')
程序运行截图:
查找10000000以内的素数用时约两秒,还算可以。但感觉还有改进空间,在删除倍数那里,只删除奇数倍实际上还是有不必要的工作的,因为不是所有的奇数倍都在6n-1和6n+1这两个数列中。
如果有什么不懂的地方或者有什么改进的建议,欢迎留言!