【问题标题】:elisp factorial calculation gives incorrect resultelisp 阶乘计算给出不正确的结果
【发布时间】:2013-01-27 00:17:52
【问题描述】:

如果我在 emacs-lisp 中编写这个函数:

(defun factorial (n)
  (if (<= n 1)
      1
      (* n (factorial (- n 1)))))
      => factorial

它适用于像 5 或 10 这样的小数,但如果我尝试计算(阶乘 33)答案是 -1211487723752259584,这显然是错误的,所有大数都会破坏函数。在 python 中,这不会发生。是什么导致了这个问题?

【问题讨论】:

    标签: emacs elisp


    【解决方案1】:

    在处理大数字时,您始终可以调用 Emacs 的 calc 库。

    (defun factorial (n)
      (string-to-number (factorial--1 n)))
    
    (defun factorial--1 (n)
      (if (<= n 1)
          "1"
        (calc-eval (format "%s * %s"
                           (number-to-string n)
                           (factorial--1 (- n 1))))))
    
    
    ELISP> (factorial 33)  
    8.683317618811886e+036
    

    进一步阅读:

    【讨论】:

    • 我不知道如果您将评估传递给 calc,为什么要重新实现阶乘,(defun factorial (n) (calc-eval (format "%s!" n)))
    【解决方案2】:

    整数有一个specific range。超出此范围的值无法表示。这是大多数(但不是全部)编程语言的标准。通过检查 most-positive-fixnum 的值,您可以找到 Emacs Lisp 的整数数据类型在您的计算机上可以处理的最大数。

    转到您的*scratch* 缓冲区——或任何Lisp 缓冲区——并输入most-positive-fixnum。将光标放在末尾,然后按C-x C-e。在我的电脑上,我得到 2305843009213693951 作为值。你的可能不同:我在 64 位机器上,这个数字大约是 2^61。 33 的阶乘的解是 8683317618811886495518194401280000000。大约是 2^86,这也超出了我的 Emacs 可以处理的范围。 (我使用Arc 来精确计算它,因为 Arc 可以表示任何大小的整数,取决于您安装的内存量等无聊的东西)。

    【讨论】:

    • 相反,下面的答案表明 Emacs 完全能够处理像阶乘 33 这样的计算。只需执行(calc-eval "33!") 并自己检查。
    • kotchwane: calc 之所以能够做到这一点,是因为它没有依赖于 Emacs 的本机整数实现。然而在最近(从 27.1 开始)Emacs 已经获得了对 bignums 的原生支持(通过 GNU 多精度 (GMP) 库),这意味着整数实际上可以是任意大小。不知道calc是继续使用自己的实现,还是修改为使用新的原生bignums。
    【解决方案3】:

    最简单的解决方案似乎是保罗的解决方案:

    (defun factorial (n) (calc-eval (format "%s!" n)))
    
    ELISP> (factorial 33)
    8683317618811886495518194401280000000
    

    但是,我尝试通过另一种 Calc 方式来获得乐趣,但没有使用 calc-evalstring。 因为使用 Calc 的更复杂的 Emacs Lisp 程序可以通过这种方式完成。

    Calc 的 defmathcalcFunc- 函数在 Emacs Lisp 中非常强大。

    (defmath myFact (n) (string-to-number (format-number (calcFunc-fact n))))
    
    ELISP> (calcFunc-myFact 33)
    8.683317618811886e+36
    

    【讨论】:

      【解决方案4】:

      我遇到了这个问题,寻找一种在 Elisp 中计算阶乘的快速简便的方法,最好 不实现它。

      从其他答案中,我推测它是:

      (calc-eval "10!")
      

      相当于

      (calc-eval "fact(10)")
      

      这与重新定义阶乘函数一样简洁且功能更强大。例如,您可以通过这种方式获得二项式系数:

      (calc-eval "7!/3!(7-3)!")
      

      甚至那样:

      (calc-eval "choose(7,3)")
      

      Calc 真的很值得探索。我建议在 Emacs 中做交互式教程。您可以使用C-x * t 启动它。 至于calc,你可以用C-x*c,或者M-xcalc

      【讨论】:

        猜你喜欢
        • 2014-11-22
        • 2014-09-12
        • 1970-01-01
        • 2016-11-29
        • 2019-08-13
        • 2012-11-15
        • 1970-01-01
        • 2021-11-16
        • 2017-07-02
        相关资源
        最近更新 更多