【问题标题】:recursive call resulting into overflow递归调用导致溢出
【发布时间】:2012-06-21 01:49:35
【问题描述】:

我正在尝试解决项目欧拉第二个问题。为什么下面的代码会导致堆栈溢出?我正在使用 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)

【问题讨论】:

  • 您正在递归 4000000 次(即计算第 400 万个斐波那契数),该问题仅要求斐波那契数低于 4000000。

标签: clojure


【解决方案1】:

你得到一个整数溢出(而不是堆栈溢出) 如果您使用 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

【讨论】:

  • 我刚试了400万,repl就挂了。是因为计算量大吗?
  • 我计时了,在我的桌面上花了 7.28 分钟
【解决方案2】:

这是 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])))))

看看这进展有多快。

【讨论】:

    猜你喜欢
    • 2020-12-17
    • 1970-01-01
    • 2018-06-19
    • 2012-07-24
    • 2011-02-26
    • 1970-01-01
    相关资源
    最近更新 更多