Last active
March 23, 2016 23:24
-
-
Save emlyn/e763f3321350179b392b to your computer and use it in GitHub Desktop.
Generate unbounded lazy sequence of primes in Clojure (and unbounded iterator of primes in Python)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env inlein | |
'{:dependencies [[org.clojure/clojure "1.8.0"]] | |
:jvm-opts []} | |
;; to run, use inlein: https://github.com/hyPiRion/inlein (or paste into a repl) | |
(defn primes | |
"Generate a lazy infinite sequence of primes, using method from (improved to skip even numbers): | |
https://web.archive.org/web/20150710134640/http://diditwith.net/2009/01/20/YAPESProblemSevenPart2.aspx" | |
([] | |
(cons 2 (primes 3 {}))) | |
([candidate state] | |
;; state is a map of next composites above candidate to prime factors (for primes < candidate) | |
(if-let [factors (state candidate)] | |
;; candidate is composite, recur with updated state | |
(recur (+ 2 candidate) | |
(reduce (fn [s factor] | |
;; add twice the prime factor to the candidate because both are odd, | |
;; so we skip the next multiple which will necessarily be even: | |
(update-in s [(+ candidate factor factor)] conj factor)) | |
(dissoc state candidate) | |
factors)) | |
;; candidate is prime, add it to lazy seq and recurse with updated state: | |
(lazy-seq (cons candidate (primes (+ 2 candidate) | |
;; start at candidate squared (because smaller composites will necessarily | |
;; also have smaller prime factors, so will be caught by earlier primes): | |
(assoc state (* candidate candidate) [candidate])))))))) | |
(println "The first few primes are" (take 40 (primes))) | |
(println "The hundred-thousandth prime is" (first (drop 99999 (primes)))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import defaultdict | |
from itertools import islice | |
def primes(): | |
"""Generate an infinite sequence of primes, using method from (improved to skip even numbers): | |
https://web.archive.org/web/20150710134640/http://diditwith.net/2009/01/20/YAPESProblemSevenPart2.aspx""" | |
yield 2 | |
candidate = 3 | |
# state is a map of next composites above candidate to prime factors (for primes < candidate) | |
state = defaultdict(list) | |
while True: | |
if candidate in state: | |
# candidate is composite, update state and loop | |
for factor in state[candidate]: | |
# add twice the prime factor to the candidate because bot are odd, | |
# so we skip the next multiple which will necessarily be even: | |
state[candidate + factor + factor].append(factor) | |
del state[candidate] | |
candidate += 2 | |
else: | |
# candidate is prime, yield it and update state | |
yield candidate | |
# start at candidate squared (because smaller composites will necessarily | |
# also have smaller prime factors, so will be caught by earlier primes): | |
state[candidate * candidate] = [candidate] | |
candidate += 2 | |
print 'The first few primes are', list(islice(primes(), 40)) | |
print 'The hundred-thousandth prime is', next(islice(primes(), 99999, None)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment