3

Problem 10 in Project Euler. I saw some discussion there but only for C.

I used the following code to calculate:

print . sum . sieve $ [2..2000000] where
    sieve [] = []
    sieve (x:xs) = x : sieve (filter ((/= 0) . (`mod` x)) xs)

It takes ages to calculate. I am wondering if there is any more efficient way to calculate it?

Adam Stelmaszczyk
  • 19,665
  • 4
  • 70
  • 110
swcai
  • 675
  • 5
  • 12

3 Answers3

7

Many really fast ways of calculating prime numbers in haskell is described on the haskellwiki page for Prime numbers. Specifically the second one seems to be good enough, so you might write it like this:

main = print . sum . takeWhile (< 2000000) $ primes 

primes = 2: 3: sieve (tail primes) [5,7..] 

sieve (p:ps) xs = h ++ sieve ps [x | x <- t, rem x p /= 0]  
  where (h,~(_:t)) = span (< p*p) xs 

Running it we get:

ghc --make -O2 Euler10.hs
time ./SOAns
142913828922

real    0m1.598s
user    0m1.577s
sys 0m0.017s

The wiki describes why your solution is so slow, the main reason is that a sieve is set up for each number up to 2000000, when one for each prime is sufficient.

HaskellElephant
  • 9,819
  • 4
  • 38
  • 67
6

You may find this paper and the ensuing discussion interesting. The bottom line is that your sieve implementation is not as efficient as the 'real' sieve of Eratosthenes.

bosmacs
  • 7,341
  • 4
  • 31
  • 31
0

The cleanest optimized prime sieving code I've personally seen in Haskell is in the NumberSieves package, which includes both a traditional sieve based on mutable vectors and a form of O'Neill's sieve. Don't use the horrifyingly complex code in the arithmoi package—at least some of it is currently broken and randomly produces segmentation faults.

dfeuer
  • 48,079
  • 5
  • 63
  • 167