【问题标题】:Finding primes using Sieve of Eratosthenes not working - Haskell使用 Eratosthenes 筛法寻找素数不起作用 - Haskell
【发布时间】:2014-11-10 19:55:46
【问题描述】:

这是我正在尝试使用的代码:这应该会生成最大为 100 的所有素数

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

【问题讨论】:

  • 谢谢,很有帮助
  • Jubobs:这将产生前 100 个素数。要使所有素数达到 100,请使用 takeWhile (&lt;= 100) primes
  • @John Doe,那美元是干什么用的?像这样使用库:main = print $ takeWhile (&lt; 100) primes.
  • @user3237465 您推荐使用的软件包在编译时似乎比 wiki 页面(如 6.1 和 3.10)中更快(同样不可变)的功能执行显着差课程)。其中的可变数组代码要快得多,但距离优化还很远; arithmoi package 可能应该用于此目的。
  • 埃拉托色尼筛法不使用模数来检测倍数,它使用加法(或乘法)来生成它们。

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


【解决方案1】:

代码

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

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

因此,要么用自定义谓词替换 length ... == 1,要么在检查其长度之前从列表推导中替换 take 2 元素。

【讨论】:

  • 对不起,我的主要问题是我在上面放的第一个代码。我有第二个工作,但它太慢了。打错字就完事了。我想我会删除该代码。知道为什么第一段代码不起作用吗?感谢您的帮助。
  • @JohnDoe 第一个将生成满足除数要求的所有xs 使得存在 y,z。例如,x=6 将在该列表中,因为如果我们选择 y=7, z=1,我们会得到 6*1 mod 7 == 6 /= 0。这等于说 7 不是 6 的除数,因此 6 是素数。
【解决方案2】:

你想到的可能是

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)]]]

idea,即y*z = 2*y .. min (y*y) x,所以已知的上限(x &lt;= 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 我们再次开始看到它很慢(仍然),运行在 n2.05..2.10 empirical orders of growth (在 n = 5000, 10000, 15000 处快速测试 GHCi 中的解释代码)。


至于你的第二个(现已删除)函数,可以重写,逐步提高速度,如

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 个素数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-03
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 2013-04-11
    • 1970-01-01
    • 2012-08-06
    相关资源
    最近更新 更多