program main

integer(4) :: i,j,k,m,n,d

integer(4),parameter :: mx=100000000,mx1=mx*1.1

integer(1) :: a(mx1) ! mx1拓展数组,防止写溢出

x=timef() ! 计时开始

a=0 ! a标记对应下标自然数,1为素数,否则标0

a(2:3)=1 ! 2,3 单独标记

m=2 n=sqrt(mx*1.0) ! 搜索到mx平方根

a(6-1:mx-1:6)=1 ! 以6为步长,初始化标记左右侧为素数

a(6+1:mx+1:6)=1 ! 6i,6i+2,6i+3,6i+4 等皆为合数

do i=6,n,6 ! 以6为步长,搜索素数

do j=i-1,i+1,2 ! 搜索循环节点的左右2个数

if(a(j)==0) cycle

n=j*j

d=j*2

do k=n,mx,d ! 标记搜到的素数的倍数为合数

if(mod(k,6)==3) exit  ! 标记从j*j开始,更小的已被前一个素数倍数标记

a(k)=0 ! 可以j*2为步长,跳过偶数

end do ! 遇到余数3时跳出循环,后面只对余数1或5的情形作标记

n=k+d ! 循环标记倍数的起始点

do k=n,mx,d*3 ! 按照j*2*3步长标记素数的倍数

if(a(k)/=0) a(k)=0 ! 变化周期为余数5,1,3,省却一次标记动作

if(a(k+d)/=0) a(k+d)=0 ! 使用if判断比重复标记更快

end do

end do

end do

do i=6,mx,6 ! 统计素数个数

m=m+a(i-1)+a(i+1)

end do

n=timef()*1000 ! 计时结束

write(*,'(1x,2i8,a)') m,n,' ms'! 输出个数,时间

endprogram main

 

! 2021.10.17

! 标记2到1亿所有素数,统计个数

! 算法:用埃氏筛法;素数分布特征;部分减少重复标记

! 结果:5761455 997 ms

! 硬件:I5-10210U 12G内存

! 编译:Windows10 IVF 2011