Clojure - 优化线程图减少

nha*_*nha 7 optimization reduce clojure

我有以下代码:

(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)))
Run Code Online (Sandbox Code Playgroud)

它工作得很好,只是当数字变大时它的运行时间会爆炸.在我的电脑(series-sum 2500)上可能是一(series-sum 25000)两秒,但我必须杀死我的REPL.

我尝试尽可能地移动(take n),但这还不够.我觉得我对Clojure不了解,因为我不明白为什么它会慢一点(我希望(series-sum 25000)大约需要10倍(series-sum 2500)).

有一个明显的循环/重复解决方案来优化它,但我喜欢能够打印步骤和一步((take n)看起来像docstring)的想法.

如何在保持可调试性的同时提高此代码的性能?

更好的是,我可以测量每个步骤的时间来看一个花时间吗?

lee*_*ski 8

是的,它与@ zerkms的链接有关.你映射到有理数,可能应该更好地映射到浮点数:

(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")))
Run Code Online (Sandbox Code Playgroud)

现在它工作得更快:

user> (time (series-sum 2500000))
"Elapsed time: 686.233199 msecs"
"5,95"
Run Code Online (Sandbox Code Playgroud)

  • 为了它的乐趣:传感器版本:https://www.refheap.com/110572 (2认同)

Die*_*sch 6

对于这种类型的数学运算,循环计算比使用惰性序列更快.对我来说,这比其他答案快一个数量级:

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

注意:你不需要str因为format返回一个字符串.

编辑:当然这不是原始问题中代码的主要问题.大部分改进来自消除理性,如另一个答案所示.这只是进一步的优化.