2012-03-26 22 views
5

arasındaki hızda böyle bir fark var Neden döngü yöntemi ve clojure içinde yineleme yöntemi arasındaki hızda böyle bir fark olduğu hakkında bir sorum var. Ben http://www.learningclojure.com/2010/02/clojure-dojo-2-what-about-numbers-that.html yılında öğretici takip ve Heron yöntemi kullanılarak iki kare kök yöntemleri tanımlanmıştır:Neden Clojure'ın döngü ve yineleme yöntemleri

(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" 

İki yöntem arasındaki hız yaklaşık bir x10 artış olduğunu ve neden yüzeyinin altında neler olduğunu merak ediyorum İkisi de çok mu etkilendi?

+0

içindir, ilk önce sqrt2'nin bir yazım hatası mı olduğunu varsayalım? Ayrıca, yararlı sonuçlar elde etmek için zamanlamaları birkaç kez tekrarlamanız gerekir (jvm optimize etmek için zaman alır). Birinin daha yavaş olduğu gerçeğini değiştirmez, ancak sayıları önemli ölçüde değiştirir. –

+0

Yep ... şimdi düzeltildi ... 10000 kere yeterli değil mi? – zcaudate

+0

Emin değilim, ama zamana dayalı gibi görünüyor - sanki ilk saniyede daha hızlı oluyor. Yinelemeyi denediniz mi ve çıkıştan zamana baktınız mı? –

cevap

5

Sonuçlarınız şaşırtıcıdır: döngü/tekrarlama, döngü için Clojure'daki en hızlı yapıdır.

JVM JIT'in yineleme yöntemi için akıllı bir optimizasyon gerçekleştirdiğinden şüpheliyim, ancak döngü/yineleme sürümü için değil. Clojure'da temiz işlevsel kod kullandığınızda bunun ne sıklıkla meydana gelmesi şaşırtıcıdır: optimizasyona çok uygun görünmektedir. Açıkça kullanarak çiftlerde tarafından iki sürümde önemli bir hızlanma elde edebilirsiniz

Not:

Beklendiği gibi
(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" 

, döngü/tekrarlanmasını sürümü artık hafif bir kenar vardır. Sonuçlar Clojure 1.3

+0

Döngü/yineleme işlevini kesinlikle hızlandırır ... * denetlenmeyen matematik * bayrağı ne yapar? – zcaudate

+0

ilkel işlemler için taşma kontrolünü kapatır. az miktarda ekstra hız için yararlı olan, bir dezavantajı olması durumunda bir istisna alamayacaksınız, bu yüzden biraz daha dikkatli olmalısınız. – mikera

+0

Fantastik! kesinlikle döngü/yineleme işlevini hızlandırır ... sqrt ve 67.3ms sqrt2 için 38.0ms var ... =) – zcaudate

İlgili konular