gpt4 book ai didi

clojure - 为什么 Clojure 的 loop 和 iterate 方法在速度上有如此大的差异

转载 作者:行者123 更新时间:2023-12-04 19:15:45 25 4
gpt4 key购买 nike

我有一个问题,为什么clojure中的loop方法和iterate方法在速度上会有如此大的差异。我遵循了 http://www.learningclojure.com/2010/02/clojure-dojo-2-what-about-numbers-that.html 中的教程并使用 Heron 方法定义了两个平方根方法:

(defn avg [& nums] (/ (apply + nums) (count nums)))
(defn abs [x] (if (< x 0) (- x) x))
(defn close [a b] (-> a (- b) abs (< 1e-10) ) )

(defn sqrt [num]
(loop [guess 1]
(if (close num (* guess guess))
guess
(recur (avg guess (/ num guess)))
)))

(time (dotimes [n 10000] (sqrt 10))) ;;"Elapsed time: 1169.502 msecs"


;; Calculation using the iterate method
(defn sqrt2 [number]
(first (filter #(close number (* % %))
(iterate #(avg % (/ number %)) 1.0))))

(time (dotimes [n 10000] (sqrt2 10))) ;;"Elapsed time: 184.119 msecs"

这两种方法之间的速度大约提高了 10 倍,我想知道在表面之下发生了什么导致这两种方法如此发音?

最佳答案

您的结果令人惊讶:通常 loop/recur 是 Clojure 中最快的循环构造。

我怀疑 JVM JIT 已经对 iterate 方法进行了巧妙的优化,但没有对 loop/recur 版本进行优化。当您在 Clojure 中使用干净的函数式代码时,这种情况发生的频率令人惊讶:它似乎非常适合优化。

请注意,通过显式使用 double ,您可以在两个版本中获得显着的加速:

(set! *unchecked-math* true)

(defn sqrt [num]
(loop [guess (double 1)]
(if (close num (* guess guess))
guess
(recur (double (avg guess (/ num guess)))))))

(time (dotimes [n 10000] (sqrt 10)))
=> "Elapsed time: 25.347291 msecs"


(defn sqrt2 [number]
(let [number (double number)]
(first (filter #(close number (* % %))
(iterate #(avg % (/ number %)) 1.0)))))

(time (dotimes [n 10000] (sqrt 10)))
=> "Elapsed time: 32.939526 msecs"

正如预期的那样,循环/重复版本现在略有优势。结果适用于 Clojure 1.3

关于clojure - 为什么 Clojure 的 loop 和 iterate 方法在速度上有如此大的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9865499/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com