project euler problem 14
遅延評価の方が遅くなる場合なのがこの問題。
$ echo "main=print $ foldl (+) 0 [1..10^4]" > a.hs; ghc -v0 a.hs ; sleep 1; ./a 50005000 $ echo "main=print $ foldl (+) 0 [1..10^5]" > a.hs; ghc -v0 a.hs ; sleep 1; ./a 5000050000 $ echo "main=print $ foldl (+) 0 [1..10^6]" > a.hs; ghc -v0 a.hs ; sleep 1; ./a Stack space overflow: current size 8388608 bytes. Use `+RTS -Ksize -RTS' to increase it.
10^6までメモリが持たない。
正格評価であるfoldl'を使うとできるようになる。
詳しくは http://itpro.nikkeibp.co.jp/article/COLUMN/20070403/267180/?ST=develop&P=1
$ echo "import Data.List;main=print $ foldl' (+) 0 [1..10^6]" > a.hs; ghc -v0 a.hs ; sleep 1; ./a 500000500000
これを使ってとく
import Data.List main=print $ foldl' g (1,1) [(x,f(x,1))|x<-[1..10^6]] f (n,m) |n==1=m |even n=f (div n 2,m+1) |odd n=f (n*3+1,m+1) g x y=if snd x>snd y then x else y
$ time ./14 (837799,525) real:0m48.821s,user:0m48.555s,sys:0m0.256s
自分の数より小さいものは一度解いているのにそれを再利用すればもっと速そうなので配列を勉強してみる。
array版
はじめてarrayを使ってみた
結果の再利用をしていないので実行時間もほぼ同じになった。
import Data.Array import Data.List main=print$ (\x->(x,a!x)) $ foldl' max2 1 [2..n] max2 x y | a!x > a!y = x | otherwise = y f (n,m) |n==1=m |even n=f (div n 2,m+1) |odd n=f (n*3+1,m+1) a=array (1,n) [(i,f (i,1))|i<-[1..n]] n=10^6
$ time ./14 (837799,525) real:0m49.197s,user:0m48.643s,sys:0m0.172s
とりあえずはここで終了。あとでもう少し工夫してみたい。