Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure - optimize a threaded map reduce

I have the following code :

(defn series-sum
  "Compute a series : (+ 1 1/4 1/7 1/10 1/13 1/16 ...)"
  [n]
  (->> (iterate (partial + 3) 1)
       (map #(/ 1 %))
       (take n)
       (reduce +)
       float
       (format "%.2f")
       (str)))

It is working just fine, except that it's running time explodes when numbers get big. On my computer (series-sum 2500) is maybe a second or two, but (series-sum 25000) and I have to kill my REPL.

I tried moving (take n) as far as possible, but that is not enough. I feel that I don't understand something about Clojure since I don't see why it would be slower (I would expect (series-sum 25000) to take roughly 10 times as (series-sum 2500)).

There is an obvious loop/recur solution to optimize it, but I like the idea of being able to print the steps and to have one step (the (take n) looking like the docstring).

How can I improve the performance of this code while maintaining debuggability ?

Better yet, can I measure the time of each step to see the one taking time ?

like image 693
nha Avatar asked Oct 12 '15 22:10

nha


Video Answer


1 Answers

yes, it is relevant to @zerkms's link. You map to rationals, probably should better map to floats:

(defn series-sum
  "Compute a series : (+ 1 1/4 1/7 1/10 1/13 1/16 ...)"
  [n]
  (->> (iterate (partial + 3) 1)
       (take n)
       (map #(/ 1.0 %))
       (reduce +)
       (format "%.2f")))

now it works much faster:

user> (time (series-sum 2500000))
"Elapsed time: 686.233199 msecs"
"5,95"
like image 74
leetwinski Avatar answered Oct 04 '22 22:10

leetwinski