How to optimize this Haskell code summing up the primes in sublinear time?

后端 未结 4 1510
迷失自我
迷失自我 2021-02-18 23:11

Problem 10 from Project Euler is to find the sum of all the primes below given n.

I solved it simply by summing up the primes generated by the sieve of Eratosth

4条回答
  •  挽巷
    挽巷 (楼主)
    2021-02-18 23:54

    Try this and let me know how fast it is:

    -- sum of primes
    
    import Control.Monad (forM_, when)
    import Control.Monad.ST
    import Data.Array.ST
    import Data.Array.Unboxed
    
    sieve :: Int -> UArray Int Bool
    sieve n = runSTUArray $ do
        let m = (n-1) `div` 2
            r = floor . sqrt $ fromIntegral n
        bits <- newArray (0, m-1) True
        forM_ [0 .. r `div` 2 - 1] $ \i -> do
            isPrime <- readArray bits i
            when isPrime $ do
                let a = 2*i*i + 6*i + 3
                    b = 2*i*i + 8*i + 6
                forM_ [a, b .. (m-1)] $ \j -> do
                    writeArray bits j False
        return bits
    
    primes :: Int -> [Int]
    primes n = 2 : [2*i+3 | (i, True) <- assocs $ sieve n]
    
    main = do
        print $ sum $ primes 1000000
    

    You can run it on ideone. My algorithm is the Sieve of Eratosthenes, and it should be quite fast for small n. For n = 2,000,000,000, the array size may be a problem, in which case you will need to use a segmented sieve. See my blog for more information about the Sieve of Eratosthenes. See this answer for information about a segmented sieve (but not in Haskell, unfortunately).

提交回复
热议问题