diff options
Diffstat (limited to 'lisp/calc/calc-math.el')
-rw-r--r-- | lisp/calc/calc-math.el | 91 |
1 files changed, 84 insertions, 7 deletions
diff --git a/lisp/calc/calc-math.el b/lisp/calc/calc-math.el index 249dff56979..a442f2b4e03 100644 --- a/lisp/calc/calc-math.el +++ b/lisp/calc/calc-math.el @@ -32,6 +32,71 @@ (require 'calc-ext) (require 'calc-macs) + +;;; Find out how many 9s in 9.9999... will give distinct Emacs floats, +;;; then back off by one. + +(defvar math-emacs-precision + (let* ((n 1) + (x 9) + (xx (+ x (* 9 (expt 10 (- n)))))) + (while (/= x xx) + (progn + (setq n (1+ n)) + (setq x xx) + (setq xx (+ x (* 9 (expt 10 (- n))))))) + (1- n)) + "The number of digits in an Emacs float.") + +;;; Find the largest power of 10 which is an Emacs float, +;;; then back off by one so that any float d.dddd...eN +;;; is an Emacs float, for acceptable d.dddd.... + +(defvar math-largest-emacs-expt + (let ((x 1)) + (while (condition-case nil + (expt 10.0 x) + (error nil)) + (setq x (* 2 x))) + (setq x (/ x 2)) + (while (condition-case nil + (expt 10.0 x) + (error nil)) + (setq x (1+ x))) + (- x 2)) + "The largest exponent which Calc will convert to an Emacs float.") + +(defvar math-smallest-emacs-expt + (let ((x -1)) + (while (condition-case nil + (expt 10.0 x) + (error nil)) + (setq x (* 2 x))) + (setq x (/ x 2)) + (while (condition-case nil + (expt 10.0 x) + (error nil)) + (setq x (1- x))) + (+ x 2)) + "The smallest exponent which Calc will convert to an Emacs float.") + +(defun math-use-emacs-fn (fn x) + "Use the native Emacs function FN to evaluate the Calc number X. +If this can't be done, return NIL." + (and + (<= calc-internal-prec math-emacs-precision) + (math-realp x) + (let* ((fx (math-float x)) + (xpon (+ (nth 2 x) (1- (math-numdigs (nth 1 x)))))) + (and (<= math-smallest-emacs-expt xpon) + (<= xpon math-largest-emacs-expt) + (condition-case nil + (math-read-number + (number-to-string + (funcall fn + (string-to-number (math-format-number (math-float x)))))) + (error nil)))))) + (defun calc-sqrt (arg) (interactive "P") (calc-slow-wrapper @@ -310,15 +375,15 @@ (let* ((top (nthcdr (- len 2) a))) (math-isqrt-bignum-iter a - (math-scale-bignum-3 + (math-scale-bignum-digit-size (math-bignum-big (1+ (math-isqrt-small - (+ (* (nth 1 top) 1000) (car top))))) + (+ (* (nth 1 top) math-bignum-digit-size) (car top))))) (1- (/ len 2))))) (let* ((top (nth (1- len) a))) (math-isqrt-bignum-iter a - (math-scale-bignum-3 + (math-scale-bignum-digit-size (list (1+ (math-isqrt-small top))) (/ len 2))))))) @@ -341,14 +406,15 @@ (while (eq (car (setq a (cdr a))) 0)) (null a)))) -(defun math-scale-bignum-3 (a n) ; [L L S] +(defun math-scale-bignum-digit-size (a n) ; [L L S] (while (> n 0) (setq a (cons 0 a) n (1- n))) a) (defun math-isqrt-small (a) ; A > 0. [S S] - (let ((g (cond ((>= a 10000) 1000) + (let ((g (cond ((>= a 1000000) 10000) + ((>= a 10000) 1000) ((>= a 100) 100) (t 10))) g2) @@ -1402,6 +1468,7 @@ (list 'polar (math-exp-raw (nth 1 xc)) (math-from-radians (nth 2 xc))))) + ((math-use-emacs-fn 'exp x)) ((or (math-lessp-float '(float 5 -1) x) (math-lessp-float x '(float -5 -1))) (if (math-lessp-float '(float 921035 1) x) @@ -1717,10 +1784,20 @@ sum (math-lnp1-series nextsum (1+ n) nextx x)))) -(math-defcache math-ln-10 (float (bigpos 018 684 045 994 092 585 302 2) -21) +(defconst math-approx-ln-10 + (eval-when-compile + (math-read-number-simple "2.302585092994045684018")) + "An approximation for ln(10).") + +(math-defcache math-ln-10 math-approx-ln-10 (math-ln-raw-2 '(float 1 1))) -(math-defcache math-ln-2 (float (bigpos 417 309 945 559 180 147 693) -21) +(defconst math-approx-ln-2 + (eval-when-compile + (math-read-number-simple "0.693147180559945309417")) + "An approximation for ln(2).") + +(math-defcache math-ln-2 math-approx-ln-2 (math-ln-raw-3 (math-float '(frac 1 3)))) |