さて、あなたは2つのバグを持っています:あなたの
isprimerec _ 1 = False
isprimerec n t = if (n `rem` t) == 0 then False else isprimerec n (n-1)
になるはずだった
isprimerec _ 1 = True
isprimerec n t = if (n `rem` t) == 0 then False else isprimerec n (t-1)
または、リスト内包表記を使用して、
isprime n = n>1 && and [ rem n t /= 0 | t <- [n-1,n-2..2] ]
(その余分なパラメーターを内部t
化してください、それはとにかく技術的でした!-A-ha、しかしそれは何and
ですか、あなたは尋ねますか?それはちょうどこの再帰関数のようです、foldr (&&) True :: [Bool] -> Bool
。)
しかし、今ではアルゴリズムの大きな欠点が視覚的に明らかになります。間違った順序でテストします。昇順でテストすると、より高速になります。
isprime n = n>1 && and [ rem n t /= 0 | t <- [2..n-1] ]
または、で停止すると、さらに高速になりますsqrt
。
isprime n = n>1 && and [ rem n t /= 0 | t <- [2..q] ]
where q = floor (sqrt (fromIntegral n))
または、 2の後にオッズのみでテストします(すでに2でテストしているのに、なぜ6でテストするのですか?):
isprime n = n>1 && and [ rem n t /= 0 | t <- 2:[3,5..q] ]
where q = floor (sqrt (fromIntegral n))
または素数だけで(すでに3でテストしたのに、なぜ9でテストするのですか?):
isprime n = n>1 && and [ rem n t /= 0 | t <- takeWhile ((<= n).(^2)) primes ]
primes = 2 : filter isprime [3..]
そして、なぜ素数をフィルタリングするときに偶数をテストするのですか?そもそも素数を生成しない方が良いのではないでしょうか?
primes = 2 : filter isprime [3,5..]
ただし、常に2isprime
で除算をテストしますが、奇数のみをフィードします。それで、
primes = 2 : 3 : filter (noDivs (drop 1 primes)) [5,7..]
noDivs factors n = and [ rem n t /= 0 | t <- takeWhile ((<= n).(^2)) factors ]
そして、なぜそれらを後でテストして削除するためだけに、3の倍数(つまり)を生成するのですか?[9,15 ..] == map (3*) [3,5..]
-
{- [5,7..]
== [j+i | i<-[0,2..], j<-[5]] -- loop unrolling, 3x:
== [j+i | i<-[0,6..], j<-[5,7,9]]
== 5:[j+i | i<-[0,6..], j<-[7,9,11]]
== 5:[7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43, ...
\\ [ 9, 15, 21, 27, 33, 39, ...
== [j+i | i<-[0,6..], j<-[ 9 ]]
-}
primes = 2:3:5: filter (noDivs (drop 2 primes))
[j+i | i<-[0,6..], j<-[7, 11]]
事前に5の倍数をスキップすることもできます(オイラーのふるいの別のステップとして):euler (x:xs) = x : euler (xs `minus` map (x*) (x:xs))
-- [j+i | i<-[0, 6..], j<-[7, 11]] -- loop unrolling, 5x:
-- == 7:[j+i | i<-[0,30..], j<-[11,13,17,19,23,25,29,31,35,37]]
-- \\ [j+i | i<-[0,30..], j<-[ 25, 35 ]]
primes = 2:3:5:7: filter (noDivs (drop 3 primes))
[j+i | i<-[0,30..], j<-[11,13,17,19,23, 29,31, 37]]
...しかし、今のところ、それはすでに十分に進んでいます。