我对clojure还不熟悉,而且作为快速的练习,我编写了一个函数,它应该经过斐波纳契序列,直到它超过999999999 10亿次(做一些额外的计算,但并不是很重要)。我用Java编写了一些同样的东西,虽然我理解Clojure的速度比Java慢,但java程序需要35秒才能完成,Clojure程序则需要27分钟,这让我感到非常惊讶(考虑到nodejs能够在大约8分钟内完成它)。我用repl编译了这个类,并使用这个java -cp `clj -Spath` fib命令运行它。真的不确定为什么这么慢。
(defn fib
[]
(def iter (atom (long 0)))
(def tester (atom (long 0)))
(dotimes [n 1000000000]
(loop [prev (long 0)
curr (long 1)]
(when (<= prev 999999999)
(swap! iter inc)
(if (even? @iter)
(swap! tester + prev)
(swap! tester - prev))
(recur curr (+ prev curr)))))
(println (str "Done in: " @iter " Test: " @tester))
)这里是我的Java方法供参考
public static void main(String[] args) {
long iteration = 0;
int test = 0;
for (int n = 0; n < 1000000000; n++) {
int x = 0, y = 1;
while (true) {
iteration += 1;
if (iteration % 2 == 0) {
test += x;
}
else {
test -=x;
}
int i = x + y;
x = y;
y = i;
if (x > 999999999) { break; }
}
}
System.out.println("iter: " + iteration + " " + test);
}发布于 2022-04-11 20:55:59
正如其他人所注意到的,将Java代码直接转换为Clojure的过程非常缓慢。然而,如果我们编写一个Fibonacci数字生成器,它利用Clojure的优势,我们就可以得到一些短的东西,并且更多地用它的方式来完成工作。
首先,假设我们需要一个函数,它将计算Fibonacci序列的n个数(1,1,2,3,5,8,13,21,34,55,……)。要做到这一点,我们可以:
(defn fib [n]
(loop [a 1
b 0
cnt n]
(if (= cnt 1)
a
(recur (+' a b) a (dec cnt)))))它迭代地重新计算"next“Fibonacci值,直到达到所需的值为止。
给定此函数,我们可以通过将该函数映射到一系列索引值来开发一个创建Fibonacci序列值集合的函数:
(defn fib-seq [n]
(map #(fib %) (range 1 (inc n))))当然,这是计算斐波纳契值序列的一种效率极低的方法,因为对于每个值,我们必须计算所有前面的值,然后我们只保存最后一个值。如果我们想要一种更有效的方法来计算整个序列,我们可以遍历各种可能性,并将结果收集到一个集合中:
(defn fib-seq [n]
(loop [curr 1
prev 0
c '(1)]
(if (= n (count c))
(reverse c)
(let [new-curr (+' curr prev)]
(recur new-curr curr (cons new-curr c))))))这为我们提供了一种合理有效的方法来收集Fibonacci序列的值。为了测试(fib 45)中的十亿个循环(序列的第45项是超过999,999,999,999),我使用了:
(time (dotimes [n 1000000000](fib-seq 45)))它在我的硬件和操作系统上完成了17.5秒(Windows 10,双处理器英特尔i5 @ 2.6 GHz)。
https://stackoverflow.com/questions/71790601
复制相似问题