Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Last active March 1, 2019 20:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericnormand/4d87c6533772007abbc86fd6b987017d to your computer and use it in GitHub Desktop.
Save ericnormand/4d87c6533772007abbc86fd6b987017d to your computer and use it in GitHub Desktop.
PurelyFunctional.tv Newsletter - Rule of Fives

Last week's puzzle was to test the Rule of Fives from How to Measure Anything, which states that the median of a population is 93.75% likely to be between the max and the min of a sample of 5.

;; by Eric Normand
;; I used arrays for more speed (and since I never need to modify them after generation)
;; and I generate 100 random populations which I re-sample for different samples
;; generating new populations each time was time-consuming
(import '[java.util Arrays])
(defn member []
(rand 1000000))
(defn population [size]
(let [a (double-array size)]
(dotimes [i size]
(aset a i (member)))
(Arrays/sort a)
a))
(defn rand-population []
(population (rand-int 10000)))
(defn sample [population n]
(let [l (alength population)]
(loop [s #{}]
(if (= n (count s))
(map #(aget population %) s)
(recur (conj s (rand-int l)))))))
(defn median [p]
(let [mid (quot (alength p) 2)]
(if (odd? (alength p))
(aget p mid)
(/ (+ (aget p mid) (aget p (dec mid))) 2.0))))
(defn median-within? [s p]
(let [m (median p)
mn (apply min s)
mx (apply max s)]
(<= mn m mx)))
(defn run-test [size]
(let [pops (object-array (repeatedly 100 rand-population))]
(frequencies
(for [n (range size)]
(let [p (aget pops (rand-int 100))
s (sample p 5)]
(median-within? s p))))))
;; => (run-test 1000000)
;; {true 938044, false 61956}
;; => (run-test 1000000)
;; {true 938152, false 61848}
;; => (run-test 1000000)
;; {true 938437, false 61563}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment