//Incremental Sieve of Erotasthenes based on the DotNet hash based mutable Dictionary class
//Similar to http://d...content-available-to-author-only...h.net/CommentView,guid,82535152-f7e2-4051-afd6-2330aea0bdf9.aspx#commentstart
//but with opimizations of wheel factorization, delayed adding base primes, and a more efficient use of sequences
//#time
[<RequireQualifiedAccess>]
module Dict =
let empty = null
let inline tryFind k (m:System.Collections.Generic.Dictionary<_,_>) =
if m = null then None else let (found,v) = m.TryGetValue k in if found then Some v else None
let inline add k v (m:System.Collections.Generic.Dictionary<_,_>) =
let nm = if m = null then new System.Collections.Generic.Dictionary<_,_>() else m in nm.[k] <- v; nm
let
inline remove k
(m
:System.
Collections.
Generic.
Dictionary<_
,_
>) = m.
Remove k
|> ignore
; m
type cullstate = struct val p:uint32 val pi:int new(p,pi) = { p=p;pi=pi } end
type CIS<'T> = class val v:'T val cont:unit->CIS<'T> new(v,cont) = { v=v;cont=cont } end
let primesDWSE() =
let WHLPRMS = [| 2u;3u;5u;7u |] in let FSTPRM = 11u in let WHLCRC = int (WHLPRMS |> Seq.fold (*) 1u) >>> 1
let WHLLMT = int (WHLPRMS |> Seq.fold (fun o n->o*(n-1u)) 1u) - 1
let WHLPTRN =
let wp = Array.zeroCreate (WHLLMT+1)
let gaps (a:int[]) = let rec gap i acc = if a.[i]=0 then gap (i+1) (acc+1uy) else acc
{0..WHLCRC-1} |> Seq.fold (fun s i->
let ns = if a.[i]<>0 then wp.[s]<-2uy*gap (i+1) 1uy;(s+1) else s in ns) 0 |> ignore
Array.init (WHLCRC+1) (fun i->if WHLPRMS |> Seq.forall (fun p->(FSTPRM+uint32(i<<<1))%p<>0u)
then 1 else 0) |> gaps;wp
let inline whladv i = if i < WHLLMT then i + 1 else 0 in let inline advcnd c ci = c + uint32 WHLPTRN.[ci]
let inline advmltpl c p i = let n = c + uint32 WHLPTRN.[i] * p in if n < c then 0xFFFFFFFFu else n
let inline reinsert oldcmpst mp (cs:cullstate) =
let p,pi = cs.p,cs.pi in let cmpst,npi = advmltpl oldcmpst p pi,whladv pi
match Dict.tryFind cmpst mp with
| None -> mp |> Dict.add cmpst [cullstate(p,npi)]
| Some(facts) -> mp |> Dict.add cmpst (cullstate(p,npi)::facts)
let rec mkprm (n,wi,m,(psd:CIS<_>),q) =
let nxt,nxti = advcnd n wi,whladv wi
if nxt < n then (0u,0,(0xFFFFFFFFu,wi,m,psd,q))
else match Dict.tryFind n m with
| None -> if n < q then (n,wi,(nxt,nxti,m,psd,q))
else let bp,bpi = psd.v in let nc,nci = advmltpl n bp bpi,whladv bpi
let nsd = psd.cont() in let np,_ = nsd.v in let sqr = if np>65535u then 0xFFFFFFFFu else np*np
mkprm (nxt,nxti,(Dict.add nc [cullstate(bp,nci)] m),nsd,sqr)
| Some(skips) -> let adjdmap = skips |> List.fold (reinsert n) (m |> Dict.remove n)
mkprm (nxt,nxti,adjdmap,psd,q)
let rec pCIS p pi cont = let ap,api = advcnd p pi,whladv pi
CIS((p,pi),fun()->let (np,npi,ncont)=mkprm cont in pCIS np npi ncont)
let rec baseprimes() = CIS((FSTPRM,0),fun()->let np,npi = advcnd FSTPRM 0,whladv 0
pCIS np npi (advcnd np npi,whladv npi,Dict.empty,baseprimes(),FSTPRM*FSTPRM))
let inline genseq sd = Seq.unfold (fun (p,_,cont) -> Some(p,mkprm cont)) sd
seq { yield! WHLPRMS; yield! mkprm (FSTPRM,0,Dict.empty,baseprimes(),(FSTPRM*FSTPRM)) |> genseq }
primesDWSE() |> Seq.nth 1000000 |> printfn "%A"
Ly9JbmNyZW1lbnRhbCBTaWV2ZSBvZiBFcm90YXN0aGVuZXMgYmFzZWQgb24gdGhlIERvdE5ldCBoYXNoIGJhc2VkIG11dGFibGUgRGljdGlvbmFyeSBjbGFzcwovL1NpbWlsYXIgdG8gaHR0cDovL2QuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmgubmV0L0NvbW1lbnRWaWV3LGd1aWQsODI1MzUxNTItZjdlMi00MDUxLWFmZDYtMjMzMGFlYTBiZGY5LmFzcHgjY29tbWVudHN0YXJ0Ci8vYnV0IHdpdGggb3BpbWl6YXRpb25zIG9mIHdoZWVsIGZhY3Rvcml6YXRpb24sIGRlbGF5ZWQgYWRkaW5nIGJhc2UgcHJpbWVzLCBhbmQgYSBtb3JlIGVmZmljaWVudCB1c2Ugb2Ygc2VxdWVuY2VzCgovLyN0aW1lCls8UmVxdWlyZVF1YWxpZmllZEFjY2Vzcz5dCm1vZHVsZSBEaWN0ID0KICBsZXQgZW1wdHkgPSBudWxsCiAgbGV0IGlubGluZSB0cnlGaW5kIGsgKG06U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeTxfLF8+KSA9CiAgICBpZiBtID0gbnVsbCB0aGVuIE5vbmUgZWxzZSBsZXQgKGZvdW5kLHYpID0gbS5UcnlHZXRWYWx1ZSBrIGluIGlmIGZvdW5kIHRoZW4gU29tZSB2IGVsc2UgTm9uZQogIGxldCBpbmxpbmUgYWRkIGsgdiAobTpTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5EaWN0aW9uYXJ5PF8sXz4pID0KICAgIGxldCBubSA9IGlmIG0gPSBudWxsIHRoZW4gbmV3IFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnk8XyxfPigpIGVsc2UgbSBpbiBubS5ba10gPC0gdjsgbm0KICBsZXQgaW5saW5lIHJlbW92ZSBrIChtOlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnk8XyxfPikgPSBtLlJlbW92ZSBrIHw+IGlnbm9yZTsgbQoKdHlwZSBjdWxsc3RhdGUgPSBzdHJ1Y3QgdmFsIHA6dWludDMyIHZhbCBwaTppbnQgbmV3KHAscGkpID0geyBwPXA7cGk9cGkgfSBlbmQKdHlwZSBDSVM8J1Q+ID0gY2xhc3MgdmFsIHY6J1QgdmFsIGNvbnQ6dW5pdC0+Q0lTPCdUPiBuZXcodixjb250KSA9IHsgdj12O2NvbnQ9Y29udCB9IGVuZApsZXQgcHJpbWVzRFdTRSgpID0KICBsZXQgV0hMUFJNUyA9IFt8IDJ1OzN1OzV1Ozd1IHxdIGluIGxldCBGU1RQUk0gPSAxMXUgaW4gbGV0IFdITENSQyA9IGludCAoV0hMUFJNUyB8PiBTZXEuZm9sZCAoKikgMXUpID4+PiAxCiAgbGV0IFdITExNVCA9IGludCAoV0hMUFJNUyB8PiBTZXEuZm9sZCAoZnVuIG8gbi0+byoobi0xdSkpIDF1KSAtIDEKICBsZXQgV0hMUFRSTiA9CiAgICBsZXQgd3AgPSBBcnJheS56ZXJvQ3JlYXRlIChXSExMTVQrMSkKICAgIGxldCBnYXBzIChhOmludFtdKSA9IGxldCByZWMgZ2FwIGkgYWNjID0gaWYgYS5baV09MCB0aGVuIGdhcCAoaSsxKSAoYWNjKzF1eSkgZWxzZSBhY2MKICAgICAgICAgICAgICAgICAgICAgICAgIHswLi5XSExDUkMtMX0gfD4gU2VxLmZvbGQgKGZ1biBzIGktPgogICAgICAgICAgICAgICAgICAgICAgICAgICBsZXQgbnMgPSBpZiBhLltpXTw+MCB0aGVuIHdwLltzXTwtMnV5KmdhcCAoaSsxKSAxdXk7KHMrMSkgZWxzZSBzIGluIG5zKSAwIHw+IGlnbm9yZQogICAgQXJyYXkuaW5pdCAoV0hMQ1JDKzEpIChmdW4gaS0+aWYgV0hMUFJNUyB8PiBTZXEuZm9yYWxsIChmdW4gcC0+KEZTVFBSTSt1aW50MzIoaTw8PDEpKSVwPD4wdSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW4gMSBlbHNlIDApIHw+IGdhcHM7d3AKICBsZXQgaW5saW5lIHdobGFkdiBpID0gaWYgaSA8IFdITExNVCB0aGVuIGkgKyAxIGVsc2UgMCBpbiBsZXQgaW5saW5lIGFkdmNuZCBjIGNpID0gYyArIHVpbnQzMiBXSExQVFJOLltjaV0KICBsZXQgaW5saW5lIGFkdm1sdHBsIGMgcCBpID0gbGV0IG4gPSBjICsgdWludDMyIFdITFBUUk4uW2ldICogcCBpbiBpZiBuIDwgYyB0aGVuIDB4RkZGRkZGRkZ1IGVsc2UgbgogIGxldCBpbmxpbmUgcmVpbnNlcnQgb2xkY21wc3QgbXAgKGNzOmN1bGxzdGF0ZSkgPQogICAgbGV0IHAscGkgPSBjcy5wLGNzLnBpIGluIGxldCBjbXBzdCxucGkgPSBhZHZtbHRwbCBvbGRjbXBzdCBwIHBpLHdobGFkdiBwaQogICAgbWF0Y2ggRGljdC50cnlGaW5kIGNtcHN0IG1wIHdpdGgKICAgICAgfCBOb25lIC0+IG1wIHw+IERpY3QuYWRkIGNtcHN0IFtjdWxsc3RhdGUocCxucGkpXQogICAgICB8IFNvbWUoZmFjdHMpIC0+IG1wIHw+IERpY3QuYWRkIGNtcHN0IChjdWxsc3RhdGUocCxucGkpOjpmYWN0cykKICBsZXQgcmVjIG1rcHJtIChuLHdpLG0sKHBzZDpDSVM8Xz4pLHEpID0KICAgIGxldCBueHQsbnh0aSA9IGFkdmNuZCBuIHdpLHdobGFkdiB3aQogICAgaWYgbnh0IDwgbiB0aGVuICgwdSwwLCgweEZGRkZGRkZGdSx3aSxtLHBzZCxxKSkKICAgIGVsc2UgbWF0Y2ggRGljdC50cnlGaW5kIG4gbSB3aXRoCiAgICAgICAgICAgfCBOb25lIC0+IGlmIG4gPCBxIHRoZW4gKG4sd2ksKG54dCxueHRpLG0scHNkLHEpKQogICAgICAgICAgICAgICAgICAgICBlbHNlIGxldCBicCxicGkgPSBwc2QudiBpbiBsZXQgbmMsbmNpID0gYWR2bWx0cGwgbiBicCBicGksd2hsYWR2IGJwaQogICAgICAgICAgICAgICAgICAgICAgICAgIGxldCBuc2QgPSBwc2QuY29udCgpIGluIGxldCBucCxfID0gbnNkLnYgaW4gbGV0IHNxciA9IGlmIG5wPjY1NTM1dSB0aGVuIDB4RkZGRkZGRkZ1IGVsc2UgbnAqbnAKICAgICAgICAgICAgICAgICAgICAgICAgICBta3BybSAobnh0LG54dGksKERpY3QuYWRkIG5jIFtjdWxsc3RhdGUoYnAsbmNpKV0gbSksbnNkLHNxcikKICAgICAgICAgICB8IFNvbWUoc2tpcHMpIC0+IGxldCBhZGpkbWFwID0gc2tpcHMgfD4gTGlzdC5mb2xkIChyZWluc2VydCBuKSAobSB8PiBEaWN0LnJlbW92ZSBuKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWtwcm0gKG54dCxueHRpLGFkamRtYXAscHNkLHEpCiAgbGV0IHJlYyBwQ0lTIHAgcGkgY29udCA9IGxldCBhcCxhcGkgPSBhZHZjbmQgcCBwaSx3aGxhZHYgcGkKICAgICAgICAgICAgICAgICAgICAgICAgICAgQ0lTKChwLHBpKSxmdW4oKS0+bGV0IChucCxucGksbmNvbnQpPW1rcHJtIGNvbnQgaW4gcENJUyBucCBucGkgbmNvbnQpCiAgbGV0IHJlYyBiYXNlcHJpbWVzKCkgPSBDSVMoKEZTVFBSTSwwKSxmdW4oKS0+bGV0IG5wLG5waSA9IGFkdmNuZCBGU1RQUk0gMCx3aGxhZHYgMAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBDSVMgbnAgbnBpIChhZHZjbmQgbnAgbnBpLHdobGFkdiBucGksRGljdC5lbXB0eSxiYXNlcHJpbWVzKCksRlNUUFJNKkZTVFBSTSkpCiAgbGV0IGlubGluZSBnZW5zZXEgc2QgPSBTZXEudW5mb2xkIChmdW4gKHAsXyxjb250KSAtPiBTb21lKHAsbWtwcm0gY29udCkpIHNkCiAgc2VxIHsgeWllbGQhIFdITFBSTVM7IHlpZWxkISBta3BybSAoRlNUUFJNLDAsRGljdC5lbXB0eSxiYXNlcHJpbWVzKCksKEZTVFBSTSpGU1RQUk0pKSB8PiBnZW5zZXEgfQoKcHJpbWVzRFdTRSgpIHw+IFNlcS5udGggMTAwMDAwMCB8PiBwcmludGZuICIlQSI=