【问题标题】:Bignum overflow error after Euler #2 attemptEuler #2 尝试后出现 Bignum 溢出错误
【发布时间】:2013-09-15 11:17:21
【问题描述】:

我尝试使用以下尾递归函数解决Euler Problem 2

(defun fib (num)
  (labels ((fib-helper (num a b)
         (cond ((or (zerop num)
                    (eql num 1))
                a)
               (t (fib-helper (decf num)
                              (+ a b)
                              a)))))
    (fib-helper num 1 1)))


(defun sum-even-fib (max)
  (labels ((helper (sum num)
         (cond ((oddp num) (helper sum (decf num)))
               ((zerop num) sum)
               (t (helper (+ sum (fib num))
                          (decf num))))))
    (helper 0 max)))

现在,当我尝试使用函数打印结果时

(defun print-fib-sum (max dir file)
  (with-open-file
      (fib-sum-str
       (make-pathname
         :name file
         :directory dir)
        :direction :output)
    (format fib-sum-str "~A~%" (sum-even-fib max))))

max 的值为4000000,我得到了错误

     ("bignum overflow" "[Condition of type SYSTEM::SIMPLE-ARITHMETIC-ERROR]" nil)

来自*slime-events*。有没有其他方法可以处理号码并打印到文件中?

【问题讨论】:

  • 编译算法后大约需要 60 分钟(几分钟的错误-我定期监视top)。
  • 看SDS的答案,然后重读问题。我已经在文本中链接了它。
  • 谢谢,会的,我一直在将术语与值混合在我的方法中。

标签: lisp stack-overflow tail-recursion bignum


【解决方案1】:

首先,几个小问题:

  1. 使用time 而不是top

  2. Common Lisp 标准不需要尾递归优化。尽管许多实现都这样做了,但并非所有实现都优化了所有情况(例如,labels)。

  3. 您的算法在 max 中是二次的,因为它为所有索引分别计算第 n 个斐波那契数。您应该改为线性。

  4. 您正在计算偶数索引的总和,而不是 even-valued numbers

现在,您看到的算术错误:第 4,000,000 个斐波那契数相当大 - 大约是 1.6^4M ~ 10^835951。它的length 大约是2,776,968

你确定你的 lisp 能代表这么大的 bignums 吗?

【讨论】:

  • bignum大小的限制不应该与可用资源有关吗?
  • @Sylwester:它确实与资源有关,但可能存在其他限制,例如,integer-length 必须小于 2^31。
  • @Bracket:如果您还有其他问题,请提出新问题。 “移动目标”问题令人沮丧并导致投票失败。
【解决方案2】:

所以我用下面的尾递归代码解决了 Euler #2:

(defun rev-sum-even-fib (max-val)
  (labels ((helper (sum a b)
             (cond ((oddp a)
                    (helper sum (+ a b) a)) 
                   ((> a max-val)
                    sum)
                   (t
                    (helper (+ sum a) (+ a b) a)))))
    (helper 0 1 0)))

这里,算法在max 中是线性的,并且在

(time (rev-sum-even-fib 4000000))

Real time: 3.4E-5 sec.
Run time: 0.0 sec.
Space: 0 Bytes

出于显而易见的原因,我省略了数字答案。

【讨论】:

  • 这里我使用了正确的 Fib 值; Fib(0)=0 和 Fib(1)=1。
  • 您不需要传递max-val,因为该变量在词法上是可用的。已编辑。
  • 您不需要引用数字,它们是自我评估
【解决方案3】:

由于 CL 不承诺它支持 TCO(例如 JVM 上的 ABCL 不支持 TCO - 尾调用优化),因此将其可移植地编写为循环是有意义的:

(defun rev-sum-even-fib (max-val)
  (loop for a = 1 then (+ a b) and b = 0 then a
        until (> a max-val)
        when (evenp a) sum a))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    • 1970-01-01
    • 2019-06-25
    • 1970-01-01
    • 2018-05-01
    • 1970-01-01
    相关资源
    最近更新 更多