使用Sierat of Eratosthenes找不到素数 - Haskell

时间:2014-11-10 19:55:47

标签: haskell functional-programming primes sieve-of-eratosthenes sieve

以下是我尝试使用的代码:这应该生成最多100个

的所有素数
sieve_primes = [x | x<-[2..100], y<-[2..50], z <-[2..25], (x*z) `mod` y /= 0]

2 个答案:

答案 0 :(得分:1)

代码

isPrime n = length [x | x<-[2..n], n `mod` x == 0] == 1

计算所有因子来计算它们。您无需计算它们:只要找到第二个因素,您就可以停止搜索而无需检查其他因素。

因此,在检查其长度之前,请先将length ... == 1替换为自定义谓词,或将take 2元素替换为列表推导。

答案 1 :(得分:0)

你的想法可能是

Prelude> [x| x<-[2..100], not $ elem x [y*z| y<-[2..50], z<-[2..25]]]
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]

这很慢。至少我们可以重新排列碎片,

Prelude> [x| let sieve=[y*z| y<-[2..50], z<-[2..25]], 
             x<-[2..100], not $ elem x sieve]
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]

对于任何远高于1000的数字(你使用500和250),这仍然非常慢。那么,为什么25(250)限制?您的代码遵循

primes = [x| x<-[2..], not $ elem x 
                       [y*z| y<-[2..x`div`2], z<-[2..min y (x`div`y)]]]

想法,即y*z = 2*y .. min (y*y) x,所以使用已知的上限(x <= n),它应该是

primesTo n = [x| let sieve=[y*z| y<-[2..n`div`2], z<-[2..min y (n`div`y)]],
                 x<-[2..n], not $ elem x sieve]

(顺便提一句,max (min y (n/y)) {y=2..n/2} = sqrt n,所以我们可以使用10而不是25,(而对于1000,则使用31而不是250)。

现在1000不是问题,只有大约10,000以上我们再次开始看到它很慢(仍然),运行在 n 2.05..2.10 {{3 (快速测试GHCi中 n = 5000,10000,15000 的解释代码)。


至于你的第二个(现已删除)功能,它可以被重写,一步一步提高速度,

isPrime n = length [x | x<-[2..n], n `mod` x == 0] == 1
          = take 1 [x | x<-[2..n], n `mod` x == 0] == [n]
          = [x | x<- takeWhile ((<=n).(^2)) [2..n], n `mod` x == 0] == []
          = and [n `mod` x > 0 | x<- takeWhile ((<=n).(^2)) (2:[3,5..n])]

现在,编译后,它可以在十分之几秒内获得前10,000个素数。