Skip to content

Instantly share code, notes, and snippets.

@citizen428
Created April 12, 2010 19:01
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 citizen428/363888 to your computer and use it in GitHub Desktop.
Save citizen428/363888 to your computer and use it in GitHub Desktop.
user=> ; generate random number
user=> (rand)
0.8545074632292601
user=> ; infinite list of random numbers
user=> ; make sure to set *print-length*
user=> (set! *print-length* 10)
10
user=> (repeatedly rand)
(0.13569783475252373 0.585868618595554 0.7048671603900427 0.1440943435265447 0.24546858003727567 0.15406959135696596 0.41117257771529947 0.1115848319639422 0.669215744258339 0.1521494621978804 ...)
user=> ; get the reductions function from seq-utils
user=> (use '[clojure.contrib.seq-utils :only (reductions)])
nil
user=> ; example output
user=> (reductions + (repeatedly rand))
(0.41005883808810484 1.181004457271026 1.683921783958707 1.8089826384110315 2.665952641217805 3.1313294137408696 3.910840785170331 4.556861781354299 4.684333796200002 5.366467630925037 ...)
user=> ; take from this list while < 1
user=> (take-while #(< % 1) (reductions + (repeatedly rand)))
(0.15208609594210099 0.5025764514682954)
user=> ; the next number got us over 1, so we have to add 1 to the count
user=> (+ 1 (count (take-while #(< % 1) (reductions + (repeatedly rand)))))
2
user=> ; wrap it up in a function
user=> (defn numbers-added [] (+ 1 (count (take-while #(< % 1) (reductions + (repeatedly rand))))))
#'user/numbers-added
user=> ; example usage
user=> (numbers-added)
3
user=> ; take n elements from infinite list created with other function
user=> (defn take-n [n func] (take n (repeatedly func)))
#'user/take-n
user=> ; example usage
user=> (take-n 5 numbers-added)
(4 2 2 3 3)
user=> ; the def-ed seq will be cached
user=> (def rands (repeatedly rand))
#'user/rands
user=> rands
(0.6087015703728027 0.5133925986315239 0.6659904034658731 0.2585419462841031 0.46063953992700934 0.19370220942302052 0.15827993171228638 0.8614635645469774 0.6329769699781875 0.4159676205268511 ...)
user=> (take 5 rands)
(0.6087015703728027 0.5133925986315239 0.6659904034658731 0.2585419462841031 0.46063953992700934)
user=> (take 5 rands)
(0.6087015703728027 0.5133925986315239 0.6659904034658731 0.2585419462841031 0.46063953992700934)
user=> ; no caching
user=> (take-n 5 numbers-added)
(3 2 5 2 2)
user=> (take-n 5 numbers-added)
(2 3 2 3 4)
user=> ; calculate the average
user=> (defn average [xs] (/ (reduce + xs) (count xs)))
#'user/average
user=> ; example usage
user=> (average (take-n 10 numbers-added))
14/5
user=> (map (fn [n] (float (average (take-n n numbers-added)))) '(1000 10000 100000 1000000))
(2.727 2.7095 2.71827 2.71801)
(use '[clojure.contrib.seq-utils :only (reductions)])
(defn numbers-added
[]
(+ 1 (count (take-while #(< % 1) (reductions + (repeatedly rand))))))
(defn take-n
[n func]
(take n (repeatedly func)))
(defn average
[xs]
(/ (reduce + xs) (count xs)))
(map (fn [n] (double (average (take-n n numbers-added)))) '(1000 10000 100000 1000000))
@wlangstroth
Copy link

Have you tried using pmap on that last call? Not sure why, but it's closer to e.

@citizen428
Copy link
Author

Are you sure that's not only because of the different set of random numbers being averaged out? Have you compared several runs of map vs. pmap?

@wlangstroth
Copy link

I did, but it turns out you're right - the next batch, it turns out that was a total fluke. Sadly, pmap is only marginally faster.

Edit: excellent blog post, I had never heard of this "effect" before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment