首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么这个看似基本的clojure函数速度这么慢?

为什么这个看似基本的clojure函数速度这么慢?
EN

Stack Overflow用户
提问于 2022-04-08 01:10:33
回答 4查看 488关注 0票数 2

我对clojure还不熟悉,而且作为快速的练习,我编写了一个函数,它应该经过斐波纳契序列,直到它超过999999999 10亿次(做一些额外的计算,但并不是很重要)。我用Java编写了一些同样的东西,虽然我理解Clojure的速度比Java慢,但java程序需要35秒才能完成,Clojure程序则需要27分钟,这让我感到非常惊讶(考虑到nodejs能够在大约8分钟内完成它)。我用repl编译了这个类,并使用这个java -cp `clj -Spath` fib命令运行它。真的不确定为什么这么慢。

代码语言:javascript
运行
复制
(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方法供参考

代码语言:javascript
运行
复制
    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);
    }
EN

Stack Overflow用户

发布于 2022-04-11 20:55:59

正如其他人所注意到的,将Java代码直接转换为Clojure的过程非常缓慢。然而,如果我们编写一个Fibonacci数字生成器,它利用Clojure的优势,我们就可以得到一些短的东西,并且更多地用它的方式来完成工作。

首先,假设我们需要一个函数,它将计算Fibonacci序列的n个数(1,1,2,3,5,8,13,21,34,55,……)。要做到这一点,我们可以:

代码语言:javascript
运行
复制
(defn fib [n]
  (loop [a   1
         b   0
         cnt n]
    (if (= cnt 1)
      a
      (recur (+' a b) a (dec cnt)))))

它迭代地重新计算"next“Fibonacci值,直到达到所需的值为止。

给定此函数,我们可以通过将该函数映射到一系列索引值来开发一个创建Fibonacci序列值集合的函数:

代码语言:javascript
运行
复制
(defn fib-seq [n]
  (map #(fib %) (range 1 (inc n))))

当然,这是计算斐波纳契值序列的一种效率极低的方法,因为对于每个值,我们必须计算所有前面的值,然后我们只保存最后一个值。如果我们想要一种更有效的方法来计算整个序列,我们可以遍历各种可能性,并将结果收集到一个集合中:

代码语言:javascript
运行
复制
(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),我使用了:

代码语言:javascript
运行
复制
(time (dotimes [n 1000000000](fib-seq 45)))

它在我的硬件和操作系统上完成了17.5秒(Windows 10,双处理器英特尔i5 @ 2.6 GHz)。

票数 0
EN
查看全部 4 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71790601

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档