>...">

Clojure - Optimize Your Streaming Card

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 works great, except that its time explodes when numbers get large. On my computer (series-sum 2500) maybe a second or two, but (series-sum 25000) , and I have to kill my REPL.

I tried to (take n) as much as possible, but this is not enough. I feel like I don’t understand anything about Clojure, since I don’t understand why it will be slower (I would expect (series-sum 25000) take about 10 times like (series-sum 2500) ).

There is a specific loop / recur solution for optimizing it, but I like the idea of ​​printing the steps and (take n) one step ( (take n) looks like a docstring).

How to improve the performance of this code while maintaining debugging?

Even better, can I measure the time of each step to see what time it takes?

+7
optimization clojure reduce
source share
2 answers

yes, this refers to the @zerkms link. You focus on rational methods, it is probably better to focus on swimming:

 (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" 
+8
source share

For this type of mathematical operation, loop computation is faster than using lazy sequences. This is an order of magnitude faster than the other answer for me:

 (defn series-sum [n] (loop [i 0 acc 0.0] (if (< in) (recur (inc i) (+ acc (/ (float 1) (inc (* 3 i))))) (format "%.2f" acc)))) 

Note: you do not need str because format returns a string.

Edit: Of course, this is not the main problem with the code in the original question. Most of the improvements come from eliminating rationality, as another answer showed. This is another optimization.

+6
source share

All Articles