Sifting Primes with Haskell

OK, so I'm trying to write a Haskell program that counts primes very quickly. Presumably, I'm not the first person trying to do this. (In particular, I'm damn sure I saw some of the previous ones, but I can't find it now ...)

First, I want to count the number of primes less than 10 ^ 11. Currently, I left my program for about 15 minutes, and it is not halfway there. Some frenzied C ++ programmer claims that his program only takes 8 minutes. "> It’s clear that I'm doing something horrific wrong.

(In case this matters, my current implementation also uses IOUArray Integer Boolseveral threads to process independent subbands of the search space. Currently, it takes several seconds to remove all multiples of 2 from a 10 megabyte array ...)

Note that 10 ^ 11 is too large for 32-bit arithmetic. Also, 10 ^ 11 bits = 12.5 GB, too much data to fit into Haskell's 32-bit address space. Thus, you cannot immediately get the entire bitmap in memory. Finally, note that the number of primes less than 10 ^ 11 is just a shade of less than 2 ^ 32, so you cannot save real integers at the same time.


Edit: Apparently, I am reading time information incorrectly. What the C ++ guy actually claimed was:

  • Counted primes <10 ^ 11 takes 8 minutes using only one core, and uses 56 kernels for 56 seconds. (CPU type not specified.)

  • Counted primes <10 ^ 10 takes 5 seconds. (Do not know how many cores are used.)

Sorry for the mistake...

Edit: My source code can be found here: http://hpaste.org/72898

+5
source share
2 answers

Using the package by arithmoiexcellent StackOverflow instructor Daniel Fisher:

import Math.NumberTheory.Primes.Counting

main = print $ primeCount (10^11)

-- $ time ./arith
-- 4118054813
-- 
-- real 0m0.209s
-- user 0m0.198s
-- sys  0m0.008s

This is 40 times faster than writing your "crazy" familiar C ++; maybe he can learn something by looking at the source of Haskell ... Here are the haddock

+13
source

- ++ , 8 .

?

, 100 , , ( ), 1000, .

:

, , 10 11.

4 × 10 9 , , 2-3 , 4-6 .

. , . , , . , , , . .

:

Daniel Bernstein primegen ( ), , L1- 32 , 90 , 10 11 (234 8K ) Core i5 2410M (2,3 ). ( 2 32 , 10 9 0,49 0,64 .)

, , , 10 11 340 (sniff: -/, , 10 9 2,92 - , - 10 12 10 13 primegen:) , , , 32- GHC.

, , 8 - - , , , . , .

dafis@schwartz:~/Haskell/Repos/arithmoi> time tests/primeCount 100000000000
4118054813

real    0m0.145s
user    0m0.139s
sys     0m0.006s

, 10 ^ 11 32- . , 10 ^ 11 = 12,5 , , 32- Haskell. , .

, . 32- , - . . , L2- ( , L1, , GHC , ).

, , . , 3 , 5 .

, , 10 ^ 11 - 2 ^ 32, .

-, 2, 3 5, 3,3 , , 4 , . , , , .

( , , IOUArray Integer Bool . , 2 10 ...)

.

  • Int unsafeRead/unsafeWrite . Integer , Int, readArray/writeArray .
  • 10 , -. ( L2 - ).
  • , , 2, Integer, 10 . ?

:

10 11 . , , -, , , .

, .

-, :

vs <-
  mapM
    (\ start -> do
      let block = (start, start + block_size)
      v <- newEmptyMVar
      writeChan queue $ do
        say $ "New chunk " ++ show block
        chunk <- chunk_new block
        sieve_top base chunk
        c <- chunk_count chunk
        putMVar v c
      return v
    )
    (takeWhile (< target) $ iterate (+block_size) base_max)

base_max + k*block_size , , , target.

:

, , , , , , block_size ( 256 L2 512 ) - stdout if prime < 100 then say $ "Sieve " ++ show prime else return ().

() :

chunk_sieve :: Chunk -> Integer -> IO ()
chunk_sieve array prime = do
  (min, max) <- getBounds array
  let n0 = min `mod` prime
  let n1 = if n0 == 0 then min else min - n0 + prime
  mapM_
    (\ n -> writeArray array n (n == prime))
    (takeWhile (<= max) $ iterate (+prime) n1)

, , , , . ( Int), , True, . False True , .

10 9 . 155 (, 292s), block_size 148s, 143s. ,

mapM_
  (\ n -> writeArray array n False)
  (takeWhile (<= max) $ iterate (+prime) n1)
when (min <= prime && prime <= max) $ writeArray array prime True

131.

. , - ? , ( , Int -overflow), :

chunk_sieve :: Chunk -> Integer -> IO ()
chunk_sieve array prime = do
  (min, max) <- getBounds array
  let n0 = min `mod` prime
      n1 = if n0 == 0 then min else min - n0 + prime
      n2 = fromInteger (n1 - min)
      mx = fromInteger (max - min)
      pr = fromInteger prime
  mapM_
    (\ n -> unsafeWrite array n False)
    (takeWhile (<= mx) $ iterate (+pr) n2)
  when (min <= prime && prime <= max) $ writeArray array prime True

96 . , .

takeWhile (<= mx) $ iterate (+pr) n2

GHC , Int . , [n2, n2+pr .. mx] GHC , unboxed Int# s, 37 .

, .

chunk_count :: Chunk -> IO Integer
chunk_count array = do
    (min, max) <- getBounds array
    work min max 0
  where
    work i max count = do
      b <- readArray array i
      let count' = count + if b then 1 else 0
      evaluate count'
      let i' = i+1
      if i' > max
        then return count'
        else work i' max count'

, .

chunk_count :: Chunk -> IO Integer
chunk_count array = do
    (min, max) <- getBounds array
    work 0 (fromInteger (max-min)) 0
  where
    work i max count = do
      b <- unsafeRead array i
      let count' = count + if b then 1 else 0
      evaluate count'
      let i' = i+1
      if i' > max
        then return count'
        else work i' max count'

15 . evaluate count' work strict count. else work i' max $! count' evaluate 13 . work ( GHC, ) ,

chunk_count :: Chunk -> IO Integer
chunk_count array = do
    (min, max) <- getBounds array
    let mx = fromInteger (max-min)
        work i !ct
            | mx < i    = return ct
            | otherwise = do
                b <- unsafeRead array i
                work (i+1) (if b then ct+1 else ct)
    work 0 0

6.55 . , say $ "New chunk " ++ show block , , 6.18 .

, 0 . Word ( castIOUArray) popCount, " , ...", 4.25 ; , ,

sieve_top :: Chunk -> Chunk -> IO ()
sieve_top base chunk = work 2
  where
    work prime = do
      chunk_sieve chunk prime
      mp <- chunk_next_prime base prime
      case mp of
        Nothing -> return ()
        Just p' -> do
            (_,mx) <- getBounds chunk
            when (p'*p' <= mx) $ work p'

3,9 . , , , . , : 10 8,5 .

, . , , . , 3,75 , , . ( - - , , , , 4.55 5.3 . , , .)

- Integer GHC ( /, ), , , 10-15%.

. , . , , .

+12

All Articles