Skip to content

Instantly share code, notes, and snippets.

@tormaroe
Created April 3, 2011 17:40
Show Gist options
  • Select an option

  • Save tormaroe/900601 to your computer and use it in GitHub Desktop.

Select an option

Save tormaroe/900601 to your computer and use it in GitHub Desktop.
A test-driven implementation of conversion of numbers to and from SI-prefix in Clojure
(ns si_prefix.core
(:use clojure.test
clojure.contrib.generic.math-functions))
(def factors
(zipmap [:y :z :a :f :p :n :u :m :k :M :G :T :P :E :Z :Y]
(map (partial pow 1000)
(filter (complement zero?)
(range -8 9)))))
(with-test
(defn si->num [si]
(let [num (Float. (subs si 0 (dec (count si))))
prefix (keyword (str (last si)))]
(* num
(prefix factors))))
(testing "Simple numbers"
(is (approx= (si->num "1y") 0.000000000000000000000001
0.000000000000000000000000000000000000001))
(is (approx= (si->num "1z") 0.000000000000000000001
0.000000000000000000000000000000000001))
(is ( = (si->num "1a") 0.000000000000000001))
(is ( = (si->num "1f") 0.000000000000001))
(is ( = (si->num "1p") 0.000000000001))
(is ( = (si->num "1n") 0.000000001))
(is ( = (si->num "1u") 0.000001))
(is ( = (si->num "1m") 0.001))
(is ( = (si->num "1k") 1000))
(is ( = (si->num "1M") 1000000))
(is ( = (si->num "1G") 1000000000))
(is ( = (si->num "1T") 1000000000000))
(is ( = (si->num "1P") 1000000000000000))
(is ( = (si->num "1E") 1000000000000000000))
(is ( = (si->num "1Z") 1000000000000000000000))
(is ( = (si->num "1Y") 1000000000000000000000000)))
(testing "Some complex numbers"
(is ( = (si->num "11k") 11000.0))
(is (approx= (si->num "1.024k") 1024.0
0.0001))
(is ( = (si->num "123.5M") 123500000.0 ))
(is (approx= (si->num "12.2u") 0.0000122
0.000000000001))))
(with-test
(defn num->si [num]
(let [close-num (* num 1.00000000000001)
closest-map (->> factors
(sort-by val)
(filter (fn [x] (< (val x) close-num)))
last)
prefix (name (key closest-map))
si-adjusted-num (/ num (val closest-map))]
(format "%.0f%s"
si-adjusted-num
prefix)))
(testing "Simple numbers"
(is (= (num->si 1000) "1k"))
(is (= (num->si 1000000) "1M"))
(is (= (num->si 0.000001) "1u"))
(is (= (num->si 0.000000000000001) "1f")))
(testing "Some complex numbers"
(is (= (num->si 10000) "10k"))
(is (= (num->si 11000000) "11M"))
(is (= (num->si 765432000000000000000000000000) "765432Y"))
(is (= (num->si 0.000000000000000005) "5a"))
(is (= (num->si 0.000000000000000012) "12a"))))
(run-tests)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment