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
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