我正在尝试解决项目euler第二个问题。为什么下面的代码导致堆栈溢出?我正在使用recur所以它不应该存储堆栈上的所有递归调用。
(defn sum
[[a b]]
[b (+ a b)])
(defn fib-r
([n] (fib-r n 0 [0 1]))
([n s [a b]]
(if (= n 0)
s
(let [[c d] (sum [a b])
e (if (even? c) c 0)
f (+ s e)]
(recur (dec n) f [c d])))))
(fib-r 4000000)
答案 0 :(得分:6)
你得到整数溢出(而不是堆栈溢出) 如果你使用BigInts(BigInt文字以N结尾)那么Clojure会 愉快地计算出正确的结果:
(defn fib-r
([n] (fib-r n 0N [0N 1N]))
([n s [a b]]
(if (= n 0N)
s
(let [[c d] (sum [a b])
e (if (even? c) c 0N)
f (+ s e)]
(recur (dec n) f [c d])))))
#'autotestbed.core/fib-r
autotestbed.core> (fib-r 40000)
1158997879999727672946417013062336891791160667328280503727448.... big number
答案 1 :(得分:1)
这是Clojure 1.3中的一个重大变化(有关详细信息,请参阅http://dev.clojure.org/display/doc/Enhanced+Primitive+Support)原始类型的自动升级不会自动发生。
你不必像Arthur Ulfeldt所建议的那样到处使用BigInts,你可以使用自动推广加操作+'
:
(defn sum [[a b]] [b (+' a b)])
这样做。
关于400万个案例 - 是的,这个计算很大。您可以像这样修改fib-r
函数:
(defn fib-r
([n] (fib-r n 0 [0 1]))
([n s [a b]]
(if (and (< 0 n) (zero? (mod n 100000)))
(println n))
(if (= n 0) s
(let [[c d] (sum [a b])
e (if (even? c) c 0)
f (+ s e)]
(recur (dec n) f [c d])))))
看看这有多快。