免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123
最近访问板块 发新帖
楼主: MMMIX
打印 上一主题 下一主题

Sieve of Eratosthenes 的 Haskell/Scheme 实现 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2008-09-24 20:47 |只看该作者
有点明白了

按我对第二段代码的理解,设当前素数为 p,你把后面的数分成前后两段。只用 p 来筛后段,而前段让 p 之前的素数来筛。

但是你分段的时候,是通过计算平方来判断的,这与直接拿 p 来模相比,效率不会有明显改进。而且,用 p 来模可以去掉一些合数,计算平方并不能去掉合数,仅仅是把淘汰的工作留给 p 之前的素数了。基于这些分析,第二段代码性能可能不如第一段。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
22 [报告]
发表于 2008-09-24 21:23 |只看该作者
原帖由 win_hate 于 2008-9-24 20:47 发表

按我对第二段代码的理解,设当前素数为 p,你把后面的数分成前后两段。只用 p 来筛后段,而前段让 p 之前的素数来筛。

没错,前半段是由 p 之前的素数来筛的。
但是你分段的时候,是通过计算平方来判断的,这与直接拿 p 来模相比,效率不会有明显改进。而且,用 p 来模可以去掉一些合数,计算平方并不能去掉合数,仅仅是把淘汰的工作留给 p 之前的素数了。基于这些分析,第二段代码性能可能不如第一段。

分段之后,一些取模运算可以变为比较,运算量应该会小些。

我观察到的变慢的情况主要是大量内存操作引起的,实际上,profile 数据显示,80% 甚至更多的时间都是在做垃圾回收(GC).

真正优化后的版本应该是:

  1. sieve :: [Integer] -> [Integer]
  2. sieve (x:xs) = x : sieve xs'
  3.              where
  4.                 xs' = filter isPrime xs
  5.                 isPrime y
  6.                     | y < x*x           = True
  7.                     | y `mod` x /= 0    = True
  8.                     | otherwise         = False

  9. primes = 2 : sieve [3,5..]
复制代码


这是执行结果(编译时使用 -O2 优化选项)
lee@debian:~/tmp/sieve$ time ./sieve0 10000    -- 未加平方优化的版本
104743

real        0m26.741s
user        0m26.698s
sys        0m0.024s
lee@debian:~/tmp/sieve$ time ./sieve3 10000    -- 上述加了平方优化的版本
104743

real        0m19.842s
user        0m19.733s
sys        0m0.020s

[ 本帖最后由 MMMIX 于 2008-9-24 21:48 编辑 ]

论坛徽章:
0
23 [报告]
发表于 2008-09-24 22:44 |只看该作者
我说的平方优化和你的还不大一样,学着用 Haskell 写了一个(逻辑上跟我前面的 scheme 是一致的)。


  1. isprime :: Integer->[Integer]->Bool
  2. isprime n (x:xs) | x*x > n = True
  3.                  | n `mod` x == 0 = False
  4.                  | otherwise = isprime n xs
  5.                               

  6. primes = 2: filter (\x->isprime x primes) [3..]
复制代码

[ 本帖最后由 win_hate 于 2008-9-24 22:46 编辑 ]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
24 [报告]
发表于 2008-09-25 09:18 |只看该作者
在我机器上 win_hate 这个版本比前面 MMMIX 那个在计算 10000 时快两个数量级。

  1. flw@debian:~/study$ ghc --make -O2 3mix_2.hs
  2. flw@debian:~/study$ time ./3mix_2 10000
  3. 104743

  4. real    0m4.027s
  5. user    0m3.728s
  6. sys     0m0.052s
  7. flw@debian:~/study$ ghc --make -O2 win_hate.hs
  8. flw@debian:~/study$ time ./win_hate 10000
  9. 104743

  10. real    0m0.103s
  11. user    0m0.092s
  12. sys     0m0.008s
  13. flw@debian:~/study$
复制代码


[ 本帖最后由 flw 于 2008-9-25 09:20 编辑 ]

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
25 [报告]
发表于 2008-09-25 09:31 |只看该作者
原帖由 win_hate 于 2008-9-24 22:44 发表
我说的平方优化和你的还不大一样,学着用 Haskell 写了一个(逻辑上跟我前面的 scheme 是一致的)。

明白了,这个确实可以提前过滤掉许多数字。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
26 [报告]
发表于 2008-09-25 09:39 |只看该作者
原帖由 flw 于 2008-9-25 09:18 发表
在我机器上 win_hate 这个版本比前面 MMMIX 那个在计算 10000 时快两个数量级。

嗯,我那个实现在数字增大的时候性能会急剧下降,占用的内存太多了。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
27 [报告]
发表于 2008-09-25 19:37 |只看该作者
原帖由 win_hate 于 2008-9-24 22:44 发表
我说的平方优化和你的还不大一样,学着用 Haskell 写了一个(逻辑上跟我前面的 scheme 是一致的)。

帮你润饰下

  1. isPrime :: Integer -> [Integer] -> Bool
  2. isPrime p (x:xs)
  3.     | x*x > p           = True
  4.     | p `mod` x == 0    = False
  5.     | otherwise         = isPrime p xs

  6. primes = 2 : [ p | p <- [3,5..], isPrime p primes ]
复制代码

论坛徽章:
0
28 [报告]
发表于 2008-09-25 21:36 |只看该作者
恩, list comprehension 的确是很漂亮的表达方式。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
29 [报告]
发表于 2009-05-21 10:29 |只看该作者
HackageDB 上前不久上传了一个叫做 primes 的 package, 下面是其描述:
primes: Efficient, purely functional generation of prime numbers
This Haskell library provides an efficient lazy wheel sieve for prime generation inspired by Lazy wheel sieves and spirals of primes by Colin Runciman and The Genuine Sieve of Eratosthenes by Melissa O'Neil.


http://hackage.haskell.org/cgi-bin/hackage-scripts/package/primes
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP