在简单的Clojure程序中减少内存使用量

时间:2014-06-17 15:46:25

标签: clojure

我正在尝试解决codeeval上的斐波那契问题。起初我以通常的递归方式编写它,虽然我得到了正确的输出,但我没有通过测试,因为它使用了~70MB的内存,使用限制为20MB。我找到了一个approximation formula并重新编写它以使用它认为是重堆栈使用导致我超过限制。但是,似乎没有任何减少。

(ns fibonacci.core
  (:gen-class))

(use 'clojure.java.io)

(def phi (/ (+ 1 (Math/sqrt 5)) 2))

(defn parse-int 
  "Find the first integer in the string"
  [int-str]
  (Integer. (re-find  #"\d+" int-str)))

(defn readfile
  "Read in a file of integers separated by newlines and return them as a list"
  [filename]
  (with-open [rdr (reader filename)]
    (reverse (map parse-int (into '() (line-seq rdr))))))

(defn fibonacci
  "Calculate the Fibonacci number using an approximatation of Binet's Formula. From
  http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibFormula.html"
  [term]
  (Math/round (/ (Math/pow phi term) (Math/sqrt 5))))

(defn -main
  [& args]
  (let [filename (first args)
        terms (readfile filename)]
      (loop [terms terms]
        ((comp println fibonacci) (first terms))
        (if (not (empty? (rest terms)))
          (recur (rest terms))))))

(-main (first *command-line-args*))

示例输入:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
50

示例输出:

0
1
1
2
3
5
8
13
21
34
55
89
144
233
12586269025

他们的输入显然远大于此,我无法看到它。如何修改此代码以大大减少内存使用?

编辑:这是不可能的。 Codeeval知道这个问题并正在努力。请参阅here

3 个答案:

答案 0 :(得分:4)

Clojure的Codeeval已被破坏。没有公认的Clojure解决方案listed两个月前有一个message from the company说他们仍然在解决这个问题。

织补。

答案 1 :(得分:3)

据推测,问题是输入文件非常大,而readfile函数正在内存中创建整个行列表。

避免这种情况的方法是一次处理一行,而不是保持整个序列,如:

(defn -main [& args]
  (let [filename (first args)]
    (with-open [rdr (reader filename)]
       (doseq [line (line-seq rdr)]
         (-> line parse-int fibonacci println)))))

答案 2 :(得分:-1)

您是否收到堆栈溢出错误?如果是这样,Clojure支持任意精度,因此尝试使用/'代替/可能会有所帮助。 +-*/的撇号版本旨在将数字强制转换为BigInt以防止堆栈溢出。

请参阅this question