52 lines
2.7 KiB
Clojure
52 lines
2.7 KiB
Clojure
(ns example
|
|
(:gen-class))
|
|
(defn primes-hashmap
|
|
"Infinite sequence of primes using an incremental Sieve or Eratosthenes with a Hashmap"
|
|
[]
|
|
(letfn [(nxtoddprm [c q bsprms cmpsts]
|
|
(if (>= c q) ;; only ever equal
|
|
; Update cmpsts with primes up to sqrt c
|
|
(let [p2 (* (first bsprms) 2),
|
|
nbps (next bsprms),
|
|
nbp (first nbps)]
|
|
(recur (+ c 2) (* nbp nbp) nbps (assoc cmpsts (+ q p2) p2)))
|
|
|
|
(if (contains? cmpsts c)
|
|
; Not prime
|
|
(recur (+ c 2) q bsprms
|
|
(let [adv (cmpsts c), ncmps (dissoc cmpsts c)]
|
|
(assoc ncmps
|
|
(loop [try (+ c adv)] ;; ensure map entry is unique
|
|
(if (contains? ncmps try)
|
|
(recur (+ try adv))
|
|
try))
|
|
adv)))
|
|
; prime
|
|
(cons c (lazy-seq (nxtoddprm (+ c 2) q bsprms cmpsts))))))]
|
|
(do (def baseoddprms (cons 3 (lazy-seq (nxtoddprm 5 9 baseoddprms {}))))
|
|
(cons 2 (lazy-seq (nxtoddprm 3 9 baseoddprms {}))))))
|
|
|
|
;; Number of workers (threads) based upon number of available processors
|
|
(def workers
|
|
(+ 2 (.. Runtime getRuntime availableProcessors)))
|
|
|
|
;; Generate of primorial numbers (using multiple processors)
|
|
(defn primorial [n]
|
|
(if (= n 0)
|
|
1
|
|
;(reduce mul+ (pmap #(reduce *' %) (partition-all (max workers (long (/ n workers))) (take n (primes-hashmap)))))));(*' allows for big integer arithmetic as needed)
|
|
(->> ; Threads (i.e. pipes) sequence of expressions
|
|
(take n (primes-hashmap) ) ; generate primes
|
|
(partition-all (max workers (long (/ n workers)))) ; partition primes amongst workers
|
|
(pmap #(reduce *' %)) ; Multiply primes in each worker in parallel
|
|
(reduce *')))) ; multiply results of all workers together
|
|
|
|
;; Generate and Time Output
|
|
(let [start (System/nanoTime)
|
|
elapsed-secs (fn [] (/ (- (System/nanoTime) start) 1e9))] ; System start time
|
|
(doseq [i (concat (range 10) [1e2 1e3 1e4 1e5 1e6])
|
|
:let [p (primorial i)]] ; Generate ith primorial number
|
|
(if (< i 10)
|
|
(println (format "primorial ( %7d ) = %10d" i (biginteger p))) ; Output for first 10
|
|
(println (format "primorial ( %7d ) has %8d digits\tafter %.3f secs" ; Output with time since starting for remainder
|
|
(long i) (count (str p)) (elapsed-secs))))))
|