changeset 81696:c29faa83ba3a

(calculator-expt, calculator-integer-p): New functions. (calculator-fact): Check to see if the factorial will be too large before computing it. (calculator-initial-operators): Use `calculator-expt' to compute "^". (calculator-mode): Mention that results which are too large will return inf.
author Jay Belanger <jay.p.belanger@gmail.com>
date Wed, 04 Jul 2007 04:17:21 +0000
parents 8f00c712c722
children efedc1f1fb08
files lisp/calculator.el
diffstat 1 files changed, 38 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/calculator.el	Tue Jul 03 18:17:07 2007 +0000
+++ b/lisp/calculator.el	Wed Jul 04 04:17:21 2007 +0000
@@ -278,7 +278,7 @@
     ("IC" acos (D (acos X))    x  6)
     ("IT" atan (D (atan X))    x  6)
     ("Q"  sqrt sqrt            x  7)
-    ("^"  ^    expt            2  7)
+    ("^"  ^    calculator-expt 2  7)
     ("!"  !    calculator-fact x  7)
     (";"  1/   (/ 1 X)         1  7)
     ("_"  -    -               1  8)
@@ -596,7 +596,8 @@
 `+' and `-' can be used as either binary operators or prefix unary
 operators.  Numbers can be entered with exponential notation using `e',
 except when using a non-decimal radix mode for input (in this case `e'
-will be the hexadecimal digit).
+will be the hexadecimal digit).  If the result of a calculation is too
+large (out of range for Emacs), the value of \"inf\" is returned.
 
 Here are the editing keys:
 * `RET' `='      evaluate the current expression
@@ -1779,13 +1780,43 @@
        (car calculator-last-opXY) (nth 1 calculator-last-opXY) x))
     x))
 
+(defun calculator-integer-p (x)
+  "Non-nil if X is equal to an integer."
+  (condition-case nil
+      (= x (ftruncate x))
+    (error nil)))
+
+(defun calculator-expt (x y)
+  "Compute X^Y, dealing with errors appropriately."
+  (condition-case
+      nil
+      (expt x y)
+    (domain-error 0.0e+NaN)
+    (range-error
+     (if (> y 0) 
+         (if (and
+              (< x 0)
+              (= y (truncate y))
+              (oddp (truncate y)))
+             -1.0e+INF
+           1.0e+INF)
+       0.0))
+    (error 0.0e+NaN)))
+
 (defun calculator-fact (x)
   "Simple factorial of X."
-  (let ((r (if (<= x 10) 1 1.0)))
-    (while (> x 0)
-      (setq r (* r (truncate x)))
-      (setq x (1- x)))
-    (+ 0.0 r)))
+  (if (and (>= x 0)
+           (calculator-integer-p x))
+      (if (= (calculator-expt (/ x 3.0) x) 1.0e+INF)
+          1.0e+INF
+        (let ((r (if (<= x 10) 1 1.0)))
+          (while (> x 0)
+            (setq r (* r (truncate x)))
+            (setq x (1- x)))
+          (+ 0.0 r)))
+    (if (= x 1.0e+INF)
+        x
+      0.0e+NaN)))
 
 (defun calculator-truncate (n)
   "Truncate N, return 0 in case of overflow."