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?
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" 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.