Thursday, September 19, 2019

SICP in Clojure: Chapter 1, Exercise 25

This is my Clojure solution to Chapter 1, Exercise 25:

(ns sicp.ch1.ex25
  (:require [sicp.ch1.ex22 :as sicp-ch1-ex22]
            [sicp.ch1.ex24 :as sicp-ch1-ex24]))

(defn square ; supports arbitrary precision
  [n]
  (*' n n))

(defn fast-expt ; supports arbitrary precision
  [b n]
  (cond (zero? n) 1
        (even? n) (square (fast-expt b (/ n 2)))
        :else     (*' b (fast-expt b (dec n)))))

(defn expmod
  [base exp m]
  (rem (fast-expt base exp) m))

(defn fermat-test
  [n]
  (letfn [(try-it [a]
            (= (expmod a n n) a))]
    (try-it (inc (rand-int (dec n))))))

(defn fast-prime?
  [n times]
  (cond (zero? times)   true
        (fermat-test n) (fast-prime? n (dec times))
        :else           false))

(defn start-prime-test
  [n start-time]
  (let [p (fast-prime? n 10)]
    (when p
      (sicp-ch1-ex22/report-prime n (- (sicp-ch1-ex22/runtime)
                                       start-time)))
    p))

(defn timed-prime-test
  [n]
  (start-prime-test n (sicp-ch1-ex22/runtime)))

(def primes [1009 1013 1019 10007 10009 10037 100003 100019 100043
             1000003 1000033 1000037])

(map sicp-ch1-ex24/timed-prime-test primes)

(map timed-prime-test (take 6 primes))

(def old-times [50052 44905 62564 53861 82539 51227 59000 60004 59868
                66958 66804 61172])

(def new-times [2082324 667264 671594 29729704 25477811 25314029])

(map #(double (/ %1 %2)) old-times new-times) ; 0.0018--0.09x disimprovement

No comments: