prime<-function(m){
x<-c(2:m)
y<-NULL
repeat{
z<-x[(x%%x[1])!=0]
y<-c(y,x[1])
if(x[1]>sqrt(m))break
x<-z
}
c(y,z)
}
primeL<-function(m){
if(m<=3L)return(seq(1,max(1,m))[-1L])
x<-seq(from=3L,to=as.integer(m+.5),by=2L)
y<-2L
stop.val<-as.integer(ceiling(sqrt(m)))
repeat{
z<-x[(x%%x[1L])!=0L]
y<-c(y,x[1L])
if(x[1]>=stop.val)break
x<-z
}
c(y,z)
}
primeS <- function(m)
{
if(m==2)cat('2')
else if(m==2)cat('2 3')
else{
a<-2:m
b<-floor(sqrt(m))
sapply(2:b,function(y){n<-seq(y^2,m,y);a[n-1]<<-0})
return(a[which(a!=0)])
}
}
primeS2 <- function(m)
{
if(m==2)cat('2')
else{
a<-c(2,seq(3,m-sum(m%%2==0),2))
b<-floor((sqrt(m)-1)/2)
if(b!=0) sapply(1:b,function(y){
n<-seq((2*y^2+2*y+1),ceiling(m/2),2*y+1);
a[n] <<- 0})
else a <- a
return(a[which(a!=0)])
}
}
all((prime(1e6)==primeS2(1e6))&
(primeL(1e6)==primeS2(1e6))&
(primeS(1e6)==primeS2(1e6)))
#[1] TRUE
system.time(prime(1e7))
system.time(primeL(1e7))
system.time(primeS(1e7))
system.time(primeS2(1e7))
# 用户 系统 流逝
#13.07 0.00 13.08
# 9.99 0.00 9.98
# 5.78 0.00 5.81
# 1.51 0.02 1.55
筛法真是古老而优雅,primeL效率更高的缘故可能在于首先就排除了所有偶数,然后用L将index固定为int。后面两种效率更高可能在于sapply()的向量化操作,找到的是素数所在的位置。不过简洁到变态的是正则表达式
perl -e'$|++;(1 x$_)!~/^1?$|^(11+?)\1+$/&&print"$_ "while ++$_'
这里还有一个80年代的线性时间素数筛法
#linear_prime_sieves
#prime[],存储n以内所有的素数,其index为pi,初值为0
#is_prime[i],表示自然数i(i<=n)是否质数,False就不是
set is_prime[] to true
for i=2 to n
if is_prime[i]=true then prime[pi++]=i
for j=0 to pi-1
if prime[j]*i>n then exit loop_j
is_prime[prime[j]*i]=false
if i mod prime[j]=0 then exit loop_j
endif
endif
来自”P. Pritchard. Linear prime-number sieves: A family tree. Science of Computer Programming, 9:17-35, 1987”。