Created
June 4, 2025 09:44
-
-
Save dexterous/431797996049cf5a76d48685d20f4da4 to your computer and use it in GitHub Desktop.
Prime Factorization in Clojure
This file contains hidden or 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
(defn factors! [n] | |
(when-not (integer? n) | |
(throw (IllegalArgumentException. | |
(format "`%s` is not a natural number." (pr-str n))))) | |
(loop [n n, c (biginteger 2), fs (transient [])] | |
(cond | |
(neg? n) (recur (- n) c (conj! fs -1)) | |
(> c n) (seq (persistent! fs)) ; XXX: only #{0, 1} | |
(> c (Math/sqrt n)) (seq (persistent! (conj! fs n))) | |
(zero? (rem n c)) (recur (/ n c) c (conj! fs c)) | |
:else (recur n (.nextProbablePrime c) fs)))) | |
(defn factors [n & {:keys [debug] :or {debug false}}] | |
(when-not (integer? n) | |
(throw (IllegalArgumentException. | |
(format "`%s` is not a natural number." (pr-str n))))) | |
(letfn [(factors* [n c] | |
(when debug | |
(println "Trying" n c)) | |
(cond | |
(neg? n) (lazy-seq (cons -1 (lazy-seq (factors* (- n) c)))) | |
(> c n) '() ; XXX: only #{0, 1} | |
(> c (Math/sqrt n)) (cons n nil) | |
(zero? (rem n c)) (lazy-seq | |
(cons c (lazy-seq (factors* (/ n c) c)))) | |
:else (lazy-seq (factors* n (.nextProbablePrime c)))))] | |
(factors* n (biginteger 2)))) | |
(defn prime? [n] | |
(= n (first (factors n)))) | |
;; utils | |
(require '[clojure.pprint :as pp] | |
'[clojure.string :as s] | |
'[clojure.set :as x]) | |
(defn check [b] | |
(if b "\uD83D\uDDF8" "\uD83D\uDDF4")) | |
(defn percent [tot val & {p :precision :or {p 3}}] | |
(let [w (int (Math/log10 tot))] | |
(format (str "%" w "s (%" (+ 4 p) "." p "f %%)") | |
val (bigdec (* (/ val tot) 100))))) | |
(defn digits [n] | |
(reverse (map #(mod % 10) | |
(take-while pos? (iterate #(Math/floorDiv % 10) n))))) | |
(defn exponent [n] | |
(let [sup-chars [\u2070 "" \u00B2 \u00B3 \u2074 | |
\u2075 \u2076 \u2077 \u2078 \u2079]] | |
(s/join (map sup-chars (digits n))))) | |
(defn math-repr [fs] | |
(->> fs | |
frequencies | |
(map (fn [[n f]] (str n (exponent f)))) | |
(s/join \u2219))) | |
(defn features [keys-to-fns coll] | |
(map (comp (partial zipmap (keys keys-to-fns)) | |
(apply juxt (vals keys-to-fns))) | |
coll)) | |
;; tests | |
(pp/print-table | |
(features {'number identity | |
'prime? (comp check prime?) | |
'eager (comp math-repr factors!) | |
'lazy (comp math-repr factors)} | |
(concat (range -5 31) | |
[129 4523202 10000000000 8976842742 Long/MAX_VALUE]))) | |
(do | |
(pp/print-table | |
(reduce #(x/join %1 %2 {'prime? 'prime?}) | |
(map #(features {'prime? key | |
(percent % %) (comp (partial percent %) val)} | |
(->> (range 1 (inc %)) | |
(pmap prime?) | |
frequencies)) | |
(map #(int (Math/pow 10 %)) (range 1 6))))) | |
(shutdown-agents)) | |
;; (do | |
;; (doseq [n (map #(int (Math/pow 10 %)) (range 1 6))] | |
;; (pp/print-table | |
;; (features {'prime? key | |
;; n (comp (partial percent n) val)} | |
;; (->> (range 1 (inc n)) | |
;; (pmap prime?) | |
;; frequencies)))) | |
;; (shutdown-agents)) | |
(pp/print-table | |
(features {'message #(try (factors %) | |
(catch IllegalArgumentException x | |
(ex-message x)))} | |
[1.0 3.2 '() [] #{} {} "foo" map (Object.)])) | |
(letfn [(blank-line [] (println)) | |
(seperator [n] (println "+-------------+" n))] | |
(blank-line) | |
(let [f (atom (factors 275 :debug true)) | |
n (atom 0)] | |
(seperator @n) | |
(while (seq @f) | |
(println "Got" (first @f)) | |
(swap! f rest) | |
(swap! n inc) | |
(seperator @n)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment