//This work improves on the ideas of Jon Harrop as of
//http://f...content-available-to-author-only...t.ca/2010/02/sieve-of-eratosthenes.html
//which fails in terms of high memory use (saves all generated primes instead of
//just the primes to the square root of the highest candidate prime, and continuously
//regenerating buffer arrays of ever increasing huge size irrespective of the CPU cache sizes)
//as well not including a generating sequence and not having the optimizations to
//only deal with odd numbers let alone using wheel factorization
// Segmented functional Sieve of Eratosthenes not using mutable state other than the
// mutable buffer array contents; sieving odds in a packed bit array
// from http://stackoverflow.com/questions/4629734/the-sieve-of-eratosthenes-in-f/17820204#17820204
// by GordonBGood
// cloned from http://i...content-available-to-author-only...e.com/l8zupF
(*let primesJH() =
let primes =
let a = ResizeArray[2]
let grow() =
let p0 = a.[a.Count-1]+1
let b = Array.create p0 true
for di in a do
let rec loop i =
if i<b.Length then
b.[i] <- false
loop(i+di)
let i0 = p0/di*di
loop(if i0<p0 then i0+di-p0 else i0-p0)
for i=0 to b.Length-1 do
if b.[i] then a.Add(p0+i)
fun n ->
while n >= a.Count do
grow()
a.[n]
Seq.initInfinite id |> Seq.map primes
primesJH() |> Seq.nth 10000000 *)
//#time
let primesAPF() =
let BUFSZ = 1<<<17 in let b = Array.create (BUFSZ>>>5) 0xFFFFFFFFu in let BUFRNG = uint32 BUFSZ<<<1
let bLUT = [| for i in 0..31 -> 1u<<<i |] //simple Look Up Tables for bit operations on uint32's
let rbLUT = bLUT |> Array.map ((^^^) 0xFFFFFFFFu)
let inline cull p s low sz (buf:uint32[]) =
let inline clrbit i (buf:uint32[]) = let w,b = i>>>5,rbLUT.[i&&&0x1F] in buf.[w] <- buf.[w]&&&b
let rec cull2 i = if i < sz then (clrbit i buf; cull2 (i+int p))
cull2 (if s>=low then int(s-low)>>>1
else let r=((low-s)>>>1)%p in if r=0u then 0 else int(p-r))
let inline testbit i (buf:uint32[]) = let w,b = i>>>5,bLUT.[i&&&0x1F] in (buf.[w]&&&b)<>0u
let baseprimes = //memoization is by the little BitArray
let LBSZ = (65537-3)>>>1 in let lb = Array.create ((LBSZ+31)>>>5) 0xFFFFFFFFu //size rounded up
let rec mkpi i = if testbit i lb then i else mkpi (i+1)
let inline maybecull p = //only cull once per new found prime
let s = p*p in if s < 65536u && testbit (int(s-3u)>>>1) lb then cull p s 3u LBSZ lb
Seq.unfold (fun i->let pi=mkpi i in let p=3u+(uint32 pi<<<1) in maybecull p;Some(p,pi+1)) 0 |> Seq.cache
let inline cullpg low = //cull composites from whole buffer page for efficiency
let max = low+BUFRNG-1u in let max = if max<low then 0xFFFFFFFFu else max
baseprimes |> Seq.takeWhile (fun p-> //force side effect of culling to limit of buffer
let s=p*p in if p>65536u || s>=max then false else true)|>Seq.iter (fun p->let s=p*p in cull p s low BUFSZ b)
let rec mkpi i low =
if i>=BUFSZ then (let nlow=low+BUFRNG in Array.fill b 0 b.Length 0xFFFFFFFFu; cullpg nlow;mkpi 0 nlow)
else (if testbit i b then (i,low) else mkpi (i+1) low)
let oddprimes = cullpg 3u; Seq.unfold (fun (i,lw) -> //force cull the first buffer page then doit
let rtn=mkpi i lw in let ni,nlw = fst rtn,snd rtn in let p=nlw+(uint32 ni<<<1)
(if p<lw then failwith "Enumerated primes past 32-bit range!!!"); Some(p,(ni+1,nlw))) (0,3u)
seq { yield 2u; yield! oddprimes }
primesAPF() |> Seq.nth 1000000 |> printfn "%A"