PI近似:为什么我的声明版本较慢?

时间:2014-04-21 23:48:48

标签: clojure

我使用该系列逼近PI:

PI Sereies

该系列的功能如下所示:

(defn- pi-series [k]
  (/ (if (even? (inc k)) 1 -1)
     (dec (* 2 k))))

然后我的系列生成器看起来像*:

(defn pi [n]
  (* 4
    (loop [k 1
           acc 0]
      (if (= k (inc n))
        acc
        (recur (inc k) 
               (+ acc (double (pi-series k))))))))

使用值pi运行999,999会产生以下结果:

(time (pi 999999))
;;=> "Elapsed time: 497.686 msecs"
;;=> 3.1415936535907734

看起来很棒,但我意识到pi可以写得更具说法性。这就是我最终得到的结果:

(defn pi-fn [n]
  (* 4 (reduce + 
               (map #(double (pi-series %)) 
                    (range 1 (inc n))))))

结果如下:

(time (pi-fn 999999))
;;=> "Elapsed time: 4431.626 msecs"
;;=> 3.1415936535907734

注意:声明性版本需要大约4秒钟。为什么呢?

为什么声明版本要慢得多?如何更新声明版本以使其与命令式版本一样快?


  • 我将pi系列的结果转换为双倍,因为使用clojure的比率类型执行速度要慢得多。

1 个答案:

答案 0 :(得分:3)

顺便说一句,您可以将交替的有限和表示为两个和的差,从而无需单独调整每个项的符号。例如,

(defn alt-sum [f n]
  (- (apply + (map f (range 1 (inc n) 2)))
     (apply + (map f (range 2 (inc n) 2)))))

(time (* 4 (alt-sum #(/ 1.0 (dec (+ % %))) 999999)))
; "Elapsed time: 195.244047 msecs"
;= 3.141593653590707

在我的笔记本电脑上pi以2500毫秒的速度运行。但是,pipi-fn(任一版本)大约运行。相同的速率(比alt-sum慢10倍)。通常情况下,pi-fn 比<{1}} 更快。你确定在第二次计时之前没有意外插入额外的9吗?反对胡安,我不认为你不止一次地迭代序列,因为这些术语是懒惰地产生的。

pi