Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

elisp factorial calculation gives incorrect result

Tags:

emacs

elisp

If I write this function in emacs-lisp:

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

It works well for small numbers like 5 or 10, but if I try and calculate (factorial 33) the answer is -1211487723752259584 which is obviously wrong, all large numbers break the function. In python this doesn't happen. What is causing this problem?

like image 924
Mike Vella Avatar asked Jan 27 '13 00:01

Mike Vella


3 Answers

You can always invoke Emacs' calc library when dealing with large numbers.

(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

Further reading:

  • http://www.masteringemacs.org/articles/2012/04/25/fun-emacs-calc/
  • C-hig (calc) RET
  • C-hig (calc) Calling Calc from Your Programs RET
like image 113
phils Avatar answered Nov 12 '22 18:11

phils


Integers have a specific range. Values outside this range can't be represented. This is pretty standard across most -- but not all -- programming languages. You can find the largest number Emacs Lisp's integer datatype can handle on your computer by checking the value of most-positive-fixnum.

Go to your *scratch* buffer -- or any Lisp buffer -- and type in most-positive-fixnum. Put the cursor at the end, then press C-x C-e. On my computer, I get 2305843009213693951 as the value. Yours might differ: I'm on a 64 bit machine, and this number is about 2^61. The solution to the factorial of 33 is 8683317618811886495518194401280000000. That's about 2^86, which is also more than my Emacs can handle. (I used Arc to calculate it exactly, because Arc can represent any size integer, subject to boring things like the amount of memory you have installed).

like image 39
zck Avatar answered Nov 12 '22 17:11

zck


The most simple solution seems to be Paul's one:

(defun factorial (n) (calc-eval (format "%s!" n)))

ELISP> (factorial 33)
8683317618811886495518194401280000000

However, I tried for fun, by another Calc way, without using calc-eval and string. Because much more complex Emacs Lisp programs with Calc can be done in this way.

Calc's defmath and calcFunc- functions are so powerful within Emacs Lisp.

(defmath myFact (n) (string-to-number (format-number (calcFunc-fact n))))

ELISP> (calcFunc-myFact 33)
8.683317618811886e+36
like image 6
RUserPassingBy Avatar answered Nov 12 '22 16:11

RUserPassingBy