]> git.rkrishnan.org Git - sicp.git/blob - src/sicp/utils.clj
section 1.3.3
[sicp.git] / src / sicp / utils.clj
1 (ns sicp.utils)
2
3 (defn square [x] (* x x))
4
5 (defn abs
6   "find absolute value of x"
7   [x]
8   (if (< x 0) (- x) x))
9
10 (defn cube [x]
11   (* x x x))
12
13 (defn twice [x]
14   (* 2 x))
15
16 (defn half [x]
17   (/ x 2))
18
19 (defn divides? [a b]
20   (= (rem b a) 0))
21
22 (defn- find-divisor [n test-divisor]
23   (cond (> (square test-divisor)  n) n
24         (divides? test-divisor n) test-divisor
25         :else (find-divisor n (inc test-divisor))))
26
27 (defn- smallest-divisor [n]
28   (find-divisor n 2))
29
30 (defn prime? [n]
31   (= (smallest-divisor n) n))
32
33 (defn gcd [a b]
34   (if (= b 0)
35     a
36     (gcd b (rem a b))))
37
38 (defn average [a b]
39   (/ (+ a b) 2.0))
40
41 (defmacro microbench
42   " Evaluates the expression n number of times, returning the average
43     time spent in computation, removing highest and lowest values.
44
45     If the body of expr returns nil, only the timing is returned otherwise
46     the result is printed - does not affect timing.
47
48     Before timings begin, a warmup is performed lasting either 1 minute or
49     1 full computational cycle, depending on which comes first."
50   [n expr] {:pre [(> n 2)]}
51   `(let [warm-up#  (let [start# (System/currentTimeMillis)]
52                      (println "Warming up!")
53                      (while (< (System/currentTimeMillis) (+ start# (* 60 1000)))
54                             (with-out-str ~expr)
55                             (System/gc))
56                      (println "Benchmarking..."))
57          timings#  (doall
58                     (for [pass# (range ~n)]
59                       (let [start#    (System/nanoTime)
60                             retr#     ~expr
61                             timing#   (/ (double (- (System/nanoTime) start#))
62                                          1000000.0)]
63                         (when retr# (println retr#))
64                         (System/gc)
65                         timing#)))
66          runtime#  (reduce + timings#)
67          highest#  (apply max timings#)
68          lowest#   (apply min timings#)]
69      (println "Total runtime: " runtime#)
70      (println "Highest time : " highest#)
71      (println "Lowest time  : " lowest#)
72      (println "Average      : " (/ (- runtime# (+ highest# lowest#))
73                                    (- (count timings#) 2)))
74      timings#))