Can the execution time of this prime number generator be improved?

后端 未结 5 2169
情书的邮戳
情书的邮戳 2020-12-30 09:22

My initial goal when writing this was to leave the smallest footprint possible. I can say with confidence that this goal has been met. Unfortunately, this leaves me with a r

5条回答
  •  滥情空心
    2020-12-30 09:56

    EDIT: updated version below, uses less memory and is faster

    Sometimes it's good to be able to mutate stuff. Here's a, admittedly rather imperative, version that trades memory for speed. Since this thread turned out to host a nice collection of prime generating functions in F#, I thought it would be nice to add mine anyway. Using a BitArray keeps memory hogging in check.

    open System.Collections
    
    let getPrimes nmax =
        let sieve = new BitArray(nmax+1, true)
        let result = new ResizeArray(nmax/10)
        let upper = int (sqrt (float nmax))   
        result.Add(2)
    
        let mutable n = 3
        while n <= nmax do
           if sieve.[n] then
               if n<=upper then 
                   let mutable i = n
                   while i <= nmax do sieve.[i] <- false; i <- i + n
               result.Add n
           n <- n + 2
        result
    

    Update:

    The code above can be optimized further: since it only uses the odd indices in the sieve, the BitArray can be reduced to half the size by indexing odd n as 2m+1. The new version is also faster:

    let getPrimes2 nmax =
        let sieve = new BitArray((nmax/2)+1, true)
        let result = new ResizeArray(nmax/10)
        let upper = int (sqrt (float nmax))   
        if nmax>1 then result.Add(2) //fixes a subtle bug for nmax < 2
    
        let mutable m = 1
        while 2*m+1 <= nmax do
           if sieve.[m] then
               let n = 2*m+1
               if n <= upper then 
                   let mutable i = m
                   while 2*i < nmax do sieve.[i] <- false; i <- i + n
               result.Add n
           m <- m + 1
        result
    

    Timing (intel core duo 2.33GHz):

    > getPrimes 2000000 |> Seq.length;;
    Real: 00:00:00.037, CPU: 00:00:00.046, GC gen0: 0, gen1: 0, gen2: 0
    val it : int = 148933
    > getPrimes2 2000000 |> Seq.length;;
    Real: 00:00:00.026, CPU: 00:00:00.031, GC gen0: 0, gen1: 0, gen2: 0
    val it : int = 148933
    

提交回复
热议问题