Reputation: 47441
I am trying to solve the project euler 2nd question. Why is the below code resulting into stack overflow ? I am using recur so it should not be storing all the recursive calls on the stack.
(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)
Upvotes: 2
Views: 96
Reputation: 1094
This was a big change made in Clojure 1.3 (see http://dev.clojure.org/display/doc/Enhanced+Primitive+Support for details) auto-promotion of primitive types does not happen automatically.
You don't have to use BigInts everywhere as Arthur Ulfeldt suggests, you can instead use auto-promoting plus operation +'
:
(defn sum [[a b]] [b (+' a b)])
This will do.
In regards to the 4 million case - yes this computation is large. You can modify your fib-r
function like this:
(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])))))
to see how fast this is going.
Upvotes: 1
Reputation: 91534
your getting an integer overflow (rather than a stack overflow) If you use BigInts (BigInt literals end with N) then Clojure will happily compute the correct result:
(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
Upvotes: 6