1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancements. ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; (c) Copyright 1982 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 (macsyma-module float
)
15 ;; EXPERIMENTAL BIGFLOAT PACKAGE VERSION 2- USING BINARY MANTISSA
16 ;; AND POWER-OF-2 EXPONENT.
17 ;; EXPONENTS MAY BE BIG NUMBERS NOW (AUG. 1975 --RJF)
18 ;; Modified: July 1979 by CWH to run on the Lisp Machine and to comment
20 ;; August 1980 by CWH to run on Multics and to install
22 ;; December 1980 by JIM to fix BIGLSH not to pass LSH a second
23 ;; argument with magnitude greater than MACHINE-FIXNUM-PRECISION.
25 ;; Number of bits of precision in a fixnum and in the fields of a flonum for
26 ;; a particular machine. These variables should only be around at eval
27 ;; and compile time. These variables should probably be set up in a prelude
28 ;; file so they can be accessible to all Macsyma files.
31 (:compile-toplevel
:load-toplevel
:execute
)
32 (defconstant +machine-fixnum-precision
+ (integer-length most-positive-fixnum
)))
36 ;; FPROUND uses this to return a second value, i.e. it sets it before
37 ;; returning. This number represents the number of binary digits its input
38 ;; bignum had to be shifted right to be aligned into the mantissa. For
39 ;; example, aligning 1 would mean shifting it FPPREC-1 places left, and
40 ;; aligning 7 would mean shifting FPPREC-3 places left.
44 ;; *DECFP = T if the computation is being done in decimal radix. NIL implies
45 ;; base 2. Decimal radix is used only during output.
49 ;; FIXME: These don't appear to be used anywhere. Remove these.
50 (defvar max-bfloat-%pi bigfloat%pi
)
51 (defvar max-bfloat-%e bigfloat%e
)
52 (defvar max-bfloat-%gamma bigfloat%gamma
)
53 (defvar max-bfloat-log2 bigfloat_log2
)
56 (declare-top (special *cancelled $bfloat
))
58 ;; Representation of a Bigfloat: ((BIGFLOAT SIMP precision) mantissa exponent)
59 ;; precision -- number of bits of precision in the mantissa.
60 ;; precision = (integer-length mantissa)
61 ;; mantissa -- a signed integer representing a fractional portion computed by
62 ;; fraction = (// mantissa (^ 2 precision)).
63 ;; exponent -- a signed integer representing the scale of the number.
64 ;; The actual number represented is (* fraction (^ 2 exponent)).
71 (defun fpprec1 (assign-var q
)
72 (declare (ignore assign-var
))
73 (if (or (not (fixnump q
)) (< q
1))
74 (merror (intl:gettext
"fpprec: value must be a positive integer; found: ~M") q
))
75 (setq fpprec
(+ 2 (integer-length (expt 10. q
)))
76 bigfloatone
($bfloat
1)
77 bigfloatzero
($bfloat
0)
78 bfhalf
(list (car bigfloatone
) (cadr bigfloatone
) 0)
79 bfmhalf
(list (car bigfloatone
) (- (cadr bigfloatone
)) 0))
82 ;; FPSCAN is called by lexical scan when a
83 ;; bigfloat is encountered. For example, 12.01B-3
84 ;; would be the result of (FPSCAN '(/1 /2) '(/0 /1) '(/- /3))
85 ;; Arguments to FPSCAN are a list of characters to the left of the
86 ;; decimal point, to the right of the decimal point, and in the exponent.
88 (defun fpscan (lft rt exp
&aux
(*read-base
* 10.
) (*m
1) (*cancelled
0))
89 (setq exp
(readlist exp
))
91 (let ((fpprec (+ 4 fpprec
(integer-length exp
)
92 (floor (1+ (* #.
(/ (log 10.0) (log 2.0)) (length lft
))))))
94 (setq temp
(add (readlist lft
)
95 (div (readlist rt
) (expt 10.
(length rt
)))))
96 ($bfloat
(cond ((> (abs exp
) 1000.
)
97 (cons '(mtimes) (list temp
(list '(mexpt) 10. exp
))))
98 (t (mul2 temp
(power 10. exp
))))))))
100 (defun dim-bigfloat (form result
)
101 (let (($lispdisp nil
))
102 (dimension-atom (maknam (fpformat form
)) result
)))
104 ;; Assume that X has the form ((BIGFLOAT ... <prec>) ...).
106 (defun bigfloat-prec (x)
107 (car (last (car x
))))
109 ;; Converts the bigfloat L to list of digits including |.| and the
110 ;; exponent marker |b|. The number of significant digits is controlled
113 (if (not (member 'simp
(cdar l
) :test
#'eq
))
114 (setq l
(cons (cons (caar l
) (cons 'simp
(cdar l
))) (cdr l
))))
115 (cond ((equal (cadr l
) 0)
116 (if (not (equal (caddr l
) 0))
117 (mtell "FPFORMAT: warning: detected an incorrect form of 0.0b0: ~M, ~M~%"
119 (list '|
0|
'|.|
'|
0|
'|b|
'|
0|
))
120 (t ;; L IS ALWAYS POSITIVE FP NUMBER
121 (let* ((extradigs (floor (1+ (quotient (integer-length (caddr l
)) #.
(/ (log 10.0) (log 2.0))))))
122 (fpprec (+ extradigs
(decimalsin (- (bigfloat-prec l
) 2))))
127 (of (bigfloat-prec l
))
130 (setq expon
(- (cadr l
) of
))
131 (setq l
(if (minusp expon
)
132 (fpquotient (intofp (car l
)) (fpintexpt 2 (- expon
) of
))
133 (fptimes* (intofp (car l
)) (fpintexpt 2 expon of
))))
134 (incf fpprec
(- extradigs
))
135 (list (fpround (car l
)) (+ (- extradigs
) *m
(cadr l
)))))
136 (let ((*print-base
* 10.
)
141 ((effective-printprec (if (or (= $fpprintprec
0) (> $fpprintprec fpprec
)) fpprec $fpprintprec
))
142 (integer-to-explode (round (car l
) (expt 10 (- fpprec effective-printprec
))))
143 (exploded-integer (explodec integer-to-explode
)))
144 ;; If the rounded integer has more digits than
145 ;; expected, we need to adjust the exponent by
146 ;; this amount. This also means we need to remove
147 ;; these extra digits so that the result has the
148 ;; desired number of digits.
149 (setf expo-adjust
(- (length exploded-integer
) effective-printprec
))
150 (when (plusp expo-adjust
)
151 (setf exploded-integer
(butlast exploded-integer expo-adjust
)))
153 (do ((l (nreverse exploded-integer
) (cdr l
)))
154 ((not (eq '|
0|
(car l
))) (nreverse l
)))
156 (nconc (ncons (car l1
)) (ncons '|.|
)
157 (or (cdr l1
) (ncons '|
0|
))
159 (explodec (+ (1- (cadr l
)) expo-adjust
))))))))
161 ;; NOTE: This is a modified version of FORMAT-EXP-AUX from CMUCL to
162 ;; support printing of bfloats.
163 (defun bfloat-format-e (stream arg colonp atp
164 &optional w d e
(k 1)
165 overflowchar
(padchar #\space
) exponentchar
)
166 (declare (ignore colonp
))
167 (flet ((exponent-value (x)
168 ;; Compute the (decimal exponent) of the bfloat number X.
169 (let* (($fpprintprec
1)
171 (marker (position '|b| f
)))
172 ;; FIXME: do something better than printing and reading
175 (format nil
"~{~A~}" (nthcdr (1+ marker
) f
)))))
176 (bfloat-to-string (x fdigits scale
)
177 ;; Print the bfloat X with FDIGITS after the decimal
178 ;; point. This means, roughly, FDIGITS+1 significant
180 (let* (($fpprintprec
(if fdigits
185 (f (fpformat (bcons (fpabs (cdr x
)))))
186 (marker (position '|b| f
))
187 (digits (remove '|.|
(subseq f
0 marker
))))
188 ;; Depending on the value of k, move the decimal
189 ;; point. DIGITS was printed assuming the decimal point
190 ;; is after the first digit. But if fdigits = 0, fpformat
191 ;; actually printed out one too many digits, so we need
193 (when (and fdigits
(zerop fdigits
))
194 (setf digits
(butlast digits
)))
198 ;; Put the leading decimal and then some zeroes
203 ;; The number is scaled by 10^k. Do this by
204 ;; putting the decimal point in the right place,
205 ;; appending zeroes if needed.
207 (cond ((> k
(length digits
))
210 (make-list (- k
(length digits
))
211 :initial-element
#\
0)
217 (subseq digits k
)))))))
218 (let* ((str (format nil
"~{~A~}" digits
))
220 (when (and fdigits
(>= fdigits len
))
221 ;; Append some zeroes to get the desired number of digits
222 (setf str
(concatenate 'string str
223 (make-string (+ 1 k
(- fdigits len
))
224 :initial-element
#\
0)))
225 (setf len
(length str
)))
228 (char= (aref str
0) #\.
)
229 (char= (aref str
(1- (length str
))) #\.
)
232 (let* ((num-expt (exponent-value arg
))
233 (expt (if (zerop (second arg
))
235 (1+ (- num-expt k
))))
236 (estr (format nil
"~D" (abs expt
)))
237 (elen (if e
(max (length estr
) e
) (length estr
)))
239 (cond ((and w overflowchar e
(> elen e
))
242 (write-char overflowchar stream
)))
252 (if (or atp
(minusp (second arg
)))
257 (format t
"d, k = ~D ~D~%" d k
)
258 (format t
"fdig = ~D, spaceleft = ~D~%" fdig spaceleft
))
260 (multiple-value-bind (fstr flen lpoint tpoint
)
261 (bfloat-to-string arg fdig
(or k
1))
263 (format t
"fstr flen lpoint tpoint = ~S ~S ~S ~S~%"
264 fstr flen lpoint tpoint
)
265 (when (and d
(zerop d
)) (setq tpoint nil
))
267 (decf spaceleft flen
)
268 ;; See CLHS 22.3.3.2. "If the parameter d is
269 ;; omitted, ... [and] if the fraction to be
270 ;; printed is zero then a single zero digit should
271 ;; appear after the decimal point." So we need to
272 ;; subtract one from here because we're going to
273 ;; add an extra 0 digit later.
274 (when (and (null d
) (char= (aref fstr
(1- flen
)) #\.
))
278 (if (or (> spaceleft
0) tpoint
)
281 (when (and tpoint
(<= spaceleft
0))
284 (format t
"w, spaceleft overflowchar = ~S ~S ~S~%"
285 w spaceleft overflowchar
)
286 (cond ((and w
(< spaceleft
0) overflowchar
)
287 ;; Significand overflow; output the overflow char
289 (write-char overflowchar stream
)))
292 (dotimes (i spaceleft
)
293 (write-char padchar stream
)))
294 (if (minusp (second arg
))
295 (write-char #\- stream
)
296 (when atp
(write-char #\
+ stream
)))
298 (write-char #\
0 stream
))
300 (write-string fstr stream
)
301 ;; Add a zero if we need it. Which means
302 ;; we figured out we need one above, or
303 ;; another condition. Basically, append a
304 ;; zero if there are no width constraints
305 ;; and if the last char to print was a
306 ;; decimal (so the trailing fraction is
310 (char= (aref fstr
(1- flen
)) #\.
)))
311 (write-char #\
0 stream
))
312 (write-char (if exponentchar
316 (write-char (if (minusp expt
) #\-
#\
+) stream
)
318 (dotimes (i (- e
(length estr
)))
319 (write-char #\
0 stream
)))
320 (write-string estr stream
)))))))))
323 ;; NOTE: This is a modified version of FORMAT-FIXED-AUX from CMUCL to
324 ;; support printing of bfloats.
325 (defun bfloat-format-f (stream number colonp atsign
&optional w d
(k 0) ovf
(pad #\space
))
326 (declare (ignore colonp
))
329 ;; Compute the (decimal exponent) of the bfloat number X.
330 (let* (($fpprintprec
1)
332 (marker (position '|b| f
)))
333 ;; FIXME: do something better than printing and reading
336 (format nil
"~{~A~}" (nthcdr (1+ marker
) f
)))))
337 (bfloat-to-string (x fdigits scale spaceleft
)
338 ;; Print the bfloat X with FDIGITS after the decimal
339 ;; point. To do this we need to know the exponent because
340 ;; fpformat always produces exponential output. If the
341 ;; exponent is E, and we want FDIGITS after the decimal
342 ;; point, we need FDIGITS + E digits printed.
343 (flet ((compute-prec (exp spaceleft
)
345 (format t
"compute-prec ~D ~D~%" exp spaceleft
)
349 (max (1- spaceleft
) (1+ exp
)))
352 (let* ((exp (+ k
(exponent-value x
)))
353 ($fpprintprec
(compute-prec exp spaceleft
))
354 (f (let ((maxima::$bftrunc nil
))
356 (format t
"printprec = ~D~%" $fpprintprec
)
357 (fpformat (bcons (fpabs (cdr x
))))))
358 (marker (position '|b| f
))
359 (digits (remove '|.|
(subseq f
0 marker
))))
360 ;; Depending on the value of scale, move the decimal
361 ;; point. DIGITS was printed assuming the decimal point
362 ;; is after the first digit. But if fdigits = 0, fpformat
363 ;; actually printed out one too many digits, so we need
366 (format t
"exp, fdigits = ~D ~D, digits = ~S~%" exp fdigits digits
)
368 (when (and fdigits
(zerop fdigits
))
369 (setf digits
(butlast digits
)))
370 ;; Figure out where the decimal point should go. An
371 ;; exponent of 0 means the decimal is after the first
374 (dotimes (k (1- (abs exp
)))
377 ((< exp
(length digits
))
379 (format t
"exp, len = ~D ~D~%" exp
(length digits
))
380 (setf digits
(concatenate 'list
381 (subseq digits
0 (1+ exp
))
383 (subseq digits
(1+ exp
)))))
385 (setf digits
(append digits
(list '|.|
)))))
386 (let* ((str (format nil
"~{~A~}" digits
))
389 (format t
"str = ~S~%" str
)
390 (when (and fdigits
(>= fdigits len
))
391 ;; Append some zeroes to get the desired number of digits
392 (setf str
(concatenate 'string str
393 (make-string (+ 1 scale
(- fdigits len
))
394 :initial-element
#\
0)))
395 (setf len
(length str
)))
398 (char= (aref str
0) #\.
)
399 (char= (aref str
(1- (length str
))) #\.
)
403 (when (and w
(or atsign
(minusp (second number
))))
405 (multiple-value-bind (str len lpoint tpoint
)
406 (bfloat-to-string number d k spaceleft
)
407 ;;if caller specifically requested no fraction digits, suppress the
408 ;;optional trailing zero
409 (when (and d
(zerop d
)) (setq tpoint nil
))
412 ;;optional leading zero
414 (if (or (> spaceleft
0) tpoint
) ;force at least one digit
417 ;;optional trailing zero
422 (cond ((and w
(< spaceleft
0) ovf
)
423 ;;field width overflow
424 (dotimes (i w
) (write-char ovf stream
))
427 (when w
(dotimes (i spaceleft
) (write-char pad stream
)))
428 (if (minusp (second number
))
429 (write-char #\- stream
)
430 (if atsign
(write-char #\
+ stream
)))
431 (when lpoint
(write-char #\
0 stream
))
432 (write-string str stream
)
433 (when tpoint
(write-char #\
0 stream
))
436 ;; NOTE: This is a modified version of FORMAT-EXP-AUX from CMUCL to
437 ;; support printing of bfloats.
438 (defun bfloat-format-g (stream arg colonp atsign
439 &optional w d e
(k 1)
440 ovf
(pad #\space
) exponentchar
)
441 (declare (ignore colonp
))
442 (flet ((exponent-value (x)
443 ;; Compute the (decimal exponent) of the bfloat number X.
444 (let* (($fpprintprec
1)
446 (marker (position '|b| f
)))
447 ;; FIXME: do something better than printing and reading
450 (format nil
"~{~A~}" (nthcdr (1+ marker
) f
)))))
451 (bfloat-to-string (x fdigits
)
452 ;; Print the bfloat X with FDIGITS after the decimal
453 ;; point. This means, roughly, FDIGITS+1 significant
455 (let* (($fpprintprec
(if fdigits
460 (f (fpformat (bcons (fpabs (cdr x
)))))
461 (marker (position '|b| f
))
462 (digits (remove '|.|
(subseq f
0 marker
))))
463 ;; Depending on the value of k, move the decimal
464 ;; point. DIGITS was printed assuming the decimal point
465 ;; is after the first digit. But if fdigits = 0, fpformat
466 ;; actually printed out one too many digits, so we need
468 (when (and fdigits
(zerop fdigits
))
469 (setf digits
(butlast digits
)))
473 ;; Put the leading decimal and then some zeroes
478 ;; The number is scaled by 10^k. Do this by
479 ;; putting the decimal point in the right place,
480 ;; appending zeroes if needed.
482 (cond ((> k
(length digits
))
485 (make-list (- k
(length digits
))
486 :initial-element
#\
0)
492 (subseq digits k
)))))))
493 (let* ((str (format nil
"~{~A~}" digits
))
495 (when (and fdigits
(>= fdigits len
))
496 ;; Append some zeroes to get the desired number of digits
497 (setf str
(concatenate 'string str
498 (make-string (+ 1 k
(- fdigits len
))
499 :initial-element
#\
0)))
500 (setf len
(length str
)))
503 (char= (aref str
0) #\.
)
504 (char= (aref str
(1- (length str
))) #\.
)
507 (let* ((n (1+ (exponent-value arg
)))
509 ;; Default d if omitted. The procedure is taken directly from
510 ;; the definition given in the manual (CLHS 22.3.3.3), and is
511 ;; not very efficient, since we generate the digits twice.
512 ;; Future maintainers are encouraged to improve on this.
514 ;; It's also not very clear whether q in the spec is the
515 ;; number of significant digits or not. I (rtoy) think it
516 ;; makes more sense if q is the number of significant digits.
517 ;; That way 1d300 isn't printed as 1 followed by 300 zeroes.
518 ;; Exponential notation would be used instead.
520 (let* ((q (1- (nth-value 1 (bfloat-to-string arg nil
)))))
521 (setq d
(max q
(min n
7)))))
522 (let* ((ee (if e
(+ e
2) 4))
523 (ww (if w
(- w ee
) nil
))
527 (format t
"d = ~A~%" d
)
528 (format t
"ee = ~A~%" ee
)
529 (format t
"ww = ~A~%" ww
)
530 (format t
"dd = ~A~%" dd
)
531 (format t
"n = ~A~%" n
))
533 ;; Use dd fraction digits, even if that would cause
534 ;; the width to be exceeded. We choose accuracy over
535 ;; width in this case.
536 (let* ((fill-char (if (bfloat-format-f stream arg nil atsign
543 (dotimes (i ee
) (write-char fill-char stream
))))
545 (bfloat-format-e stream arg nil atsign
549 ovf pad exponentchar
)))))))
551 ;; Tells you if you have a bigfloat object. BUT, if it is a bigfloat,
552 ;; it will normalize it by making the precision of the bigfloat match
553 ;; the current precision setting in fpprec. And it will also convert
554 ;; bogus zeroes (mantissa is zero, but exponent is not) to a true
557 ;; A bigfloat object looks like '((bigfloat simp <prec>) <mantissa> <exp>)
558 ;; Note bene that the simp flag is optional -- don't count on its presence.
560 (cond ((not ($bfloatp x
)) (return nil
))
561 ((= fpprec
(setq x-prec
(bigfloat-prec x
)))
562 ;; Precision matches. (Should we fix up bogus bigfloat
566 ;; Current precision is higher than bigfloat precision.
567 ;; Scale up mantissa and adjust exponent to get the
568 ;; correct precision.
569 (setq x
(bcons (list (fpshift (cadr x
) (- fpprec x-prec
))
572 ;; Current precision is LOWER than bigfloat precision.
573 ;; Round the number to the desired precision.
574 (setq x
(bcons (list (fpround (cadr x
))
575 (+ (caddr x
) *m fpprec
(- x-prec
)))))))
576 ;; Fix up any bogus zeros that we might have created.
577 (return (if (equal (cadr x
) 0) (bcons (list 0 0)) x
))))
579 (defun bigfloat2rat (x)
580 (setq x
(bigfloatp x
))
585 (setq exp
(cond ((minusp (cadr x
))
587 y
(fpration1 (cons (car x
) (fpabs (cdr x
)))))
588 (rplaca y
(* -
1 (car y
))))
591 (princ "`rat' replaced ")
592 (when sign
(princ "-"))
593 (princ (maknam (fpformat (cons (car x
) (fpabs (cdr x
))))))
599 (setq x
($bfloat
(list '(rat simp
) (car exp
) (cdr exp
))))
600 (when sign
(princ "-"))
601 (princ (maknam (fpformat (cons (car x
) (fpabs (cdr x
))))))
607 (let ((fprateps (cdr ($bfloat
(if $bftorat
608 (list '(rat simp
) 1 (exptrl 2 (1- fpprec
)))
610 (or (and (equal x bigfloatzero
) (cons 0 1))
612 (return (do ((xx x
(setq y
(invertbigfloat
613 (bcons (fpdifference (cdr xx
) (cdr ($bfloat a
)))))))
614 (num (setq a
(fpentier x
))
615 (+ (* (setq a
(fpentier y
)) num
) onum
))
616 (den 1 (+ (* a den
) oden
))
619 ((and (not (zerop den
))
622 (fpdifference (cdr x
)
623 (fpquotient (cdr ($bfloat num
))
624 (cdr ($bfloat den
))))
627 (cons num den
))))))))
629 (defun float-nan-p (x)
630 (and (floatp x
) (not (= x x
))))
632 (defun float-inf-p (x)
633 (and (floatp x
) (not (float-nan-p x
)) (beyond-extreme-values x
)))
635 (defun beyond-extreme-values (x)
636 (multiple-value-bind (most-negative most-positive
) (extreme-float-values x
)
638 ((< x
0) (< x most-negative
))
639 ((> x
0) (> x most-positive
))
642 (defun extreme-float-values (x)
643 ;; BLECHH, I HATE ENUMERATING CASES. IS THERE A BETTER WAY ??
644 (typecase x
;gcl returns an atomic list type with type-of
645 (short-float (values most-negative-short-float most-positive-short-float
))
646 (single-float (values most-negative-single-float most-positive-single-float
))
647 (double-float (values most-negative-double-float most-positive-double-float
))
648 (long-float (values most-negative-long-float most-positive-long-float
))
649 ;; NOT SURE THE FOLLOWING REALLY WORKS
650 ;; #+(and cmu double-double)
651 ;; (kernel:double-double-float
652 ;; (values most-negative-double-double-float most-positive-double-double-float))
655 ;; Convert a floating point number into a bigfloat.
658 (merror (intl:gettext
"bfloat: attempted conversion of floating point NaN (not-a-number).~%")))
660 (merror (intl:gettext
"bfloat: attempted conversion of floating-point infinity.~%")))
662 (let ((p (float-precision x
)))
664 (mtell (intl:gettext
"bfloat: converting float ~S to bigfloat.~%") x
))))
666 ;; Need to check for zero because different lisps return different
667 ;; values for integer-decode-float of a 0. In particular CMUCL
668 ;; returns 0, -1075. A bigfloat zero needs to have an exponent and
672 (multiple-value-bind (frac exp sign
)
673 (integer-decode-float x
)
674 ;; Scale frac to the desired number of bits, and adjust the
675 ;; exponent accordingly.
676 (let ((scale (- fpprec
(integer-length frac
))))
677 (list (ash (* sign frac
) scale
)
678 (+ fpprec
(- exp scale
)))))))
680 ;; Convert a bigfloat into a floating point number.
682 (let ((precision (bigfloat-prec l
))
685 (fpprec machine-mantissa-precision
)
687 ;; Round the mantissa to the number of bits of precision of the
688 ;; machine, and then convert it to a floating point fraction. We
689 ;; have 0.5 <= mantissa < 1
690 (setq mantissa
(quotient (fpround mantissa
) (expt 2.0 machine-mantissa-precision
)))
691 ;; Multiply the mantissa by the exponent portion. I'm not sure
692 ;; why the exponent computation is so complicated.
694 ;; GCL doesn't signal overflow from scale-float if the number
695 ;; would overflow. We have to do it this way. 0.5 <= mantissa <
696 ;; 1. The largest double-float is .999999 * 2^1024. So if the
697 ;; exponent is 1025 or higher, we have an overflow.
698 (let ((e (+ exponent
(- precision
) *m machine-mantissa-precision
)))
700 (merror (intl:gettext
"float: floating point overflow converting ~:M") l
)
701 (scale-float mantissa e
)))))
703 ;; New machine-independent version of FIXFLOAT. This may be buggy. - CWH
704 ;; It is buggy! On the PDP10 it dies on (RATIONALIZE -1.16066076E-7)
705 ;; which calls FLOAT on some rather big numbers. ($RATEPSILON is approx.
709 (let (($ratepsilon
(expt 2.0 (- machine-mantissa-precision
))))
710 (maxima-rationalize x
)))
712 ;; Takes a flonum arg and returns a rational number corresponding to the flonum
713 ;; in the form of a dotted pair of two integers. Since the denominator will
714 ;; always be a positive power of 2, this number will not always be in lowest
718 `((bigfloat simp
,fpprec
) .
,s
))
720 (defmfun ($bfloat
:properties
((evfun t
))) (x)
722 (cond ((bigfloatp x
))
725 ;; Handle %i specially.
726 (mul ($bfloat
1) '$%i
))
728 (member x
*builtin-numeric-constants
* :test
#'eq
))
730 ((or (atom x
) (member 'array
(cdar x
) :test
#'eq
))
732 ((eq (caar x
) 'mexpt
)
733 (if (equal (cadr x
) '$%e
)
734 (*fpexp
($bfloat
(caddr x
)))
735 (exptbigfloat ($bfloat
(cadr x
)) (caddr x
))))
736 ((eq (caar x
) 'mncexpt
)
737 (list '(mncexpt) ($bfloat
(cadr x
)) (caddr x
)))
739 (ratbigfloat (cdr x
)))
740 ((setq y
(safe-get (caar x
) 'floatprog
))
741 (funcall y
(mapcar #'$bfloat
(cdr x
))))
742 ((or (trigp (caar x
)) (arcp (caar x
)) (eq (caar x
) '$entier
))
743 (setq y
($bfloat
(cadr x
)))
745 (cond ((eq (caar x
) '$entier
) ($entier y
))
747 (setq y
($bfloat
(logarc (caar x
) y
)))
749 y
(let ($ratprint
) (fparcsimp ($rectform y
)))))
750 ((member (caar x
) '(%cot %sec %csc
) :test
#'eq
)
752 ($bfloat
(list (ncons (safe-get (caar x
) 'recip
)) y
))))
753 (t ($bfloat
(exponentialize (caar x
) y
))))
754 (subst0 (list (ncons (caar x
)) y
) x
)))
755 (t (recur-apply #'$bfloat x
)))))
757 (defprop mplus addbigfloat floatprog
)
758 (defprop mtimes timesbigfloat floatprog
)
759 (defprop %sin sinbigfloat floatprog
)
760 (defprop %cos cosbigfloat floatprog
)
761 (defprop rat ratbigfloat floatprog
)
762 (defprop %atan atanbigfloat floatprog
)
763 (defprop %tan tanbigfloat floatprog
)
764 (defprop %log logbigfloat floatprog
)
765 (defprop mabs mabsbigfloat floatprog
)
767 (defun addbigfloat (h)
768 (prog (fans tst r nfans
)
769 (setq fans
(setq tst bigfloatzero
) nfans
0)
772 (cond ((setq r
(bigfloatp (car l
)))
773 (setq fans
(bcons (fpplus (cdr r
) (cdr fans
)))))
774 (t (setq nfans
(list '(mplus) (car l
) nfans
)))))
775 (return (cond ((equal nfans
0) fans
)
776 ((equal fans tst
) nfans
)
777 (t (simplify (list '(mplus) fans nfans
)))))))
779 (defun ratbigfloat (r)
780 ;; R is a Maxima ratio, represented as a list of the numerator and
781 ;; denominator. FLOAT-RATIO doesn't like it if the numerator is 0,
782 ;; so handle that here.
785 (bcons (float-ratio r
))))
787 ;; This is borrowed from CMUCL (float-ratio-float), and modified for
788 ;; converting ratios to Maxima's bfloat numbers.
789 (defun float-ratio (x)
790 (let* ((signed-num (first x
))
791 (plusp (plusp signed-num
))
792 (num (if plusp signed-num
(- signed-num
)))
796 (declare (fixnum digits scale
))
798 ;; Strip any trailing zeros from the denominator and move it into the scale
799 ;; factor (to minimize the size of the operands.)
800 (let ((den-twos (1- (integer-length (logxor den
(1- den
))))))
801 (declare (fixnum den-twos
))
802 (decf scale den-twos
)
803 (setq den
(ash den
(- den-twos
))))
805 ;; Guess how much we need to scale by from the magnitudes of the numerator
806 ;; and denominator. We want one extra bit for a guard bit.
807 (let* ((num-len (integer-length num
))
808 (den-len (integer-length den
))
809 (delta (- den-len num-len
))
810 (shift (1+ (the fixnum
(+ delta digits
))))
811 (shifted-num (ash num shift
)))
812 (declare (fixnum delta shift
))
814 (labels ((float-and-scale (bits)
815 (let* ((bits (ash bits -
1))
816 (len (integer-length bits
)))
817 (cond ((> len digits
)
818 (assert (= len
(the fixnum
(1+ digits
))))
819 (multiple-value-bind (f0)
820 (floatit (ash bits -
1))
821 (list (first f0
) (+ (second f0
)
824 (multiple-value-bind (f0)
826 (list (first f0
) (+ (second f0
) scale
)))))))
828 (let ((sign (if plusp
1 -
1)))
829 (list (* sign bits
) 0))))
831 (multiple-value-bind (fraction-and-guard rem
)
832 (truncate shifted-num den
)
833 (let ((extra (- (integer-length fraction-and-guard
) digits
)))
834 (declare (fixnum extra
))
836 (assert (> extra
1)))
837 ((oddp fraction-and-guard
)
841 (if (zerop (logand fraction-and-guard
2))
843 (1+ fraction-and-guard
)))
844 (float-and-scale (1+ fraction-and-guard
)))))
846 (return (float-and-scale fraction-and-guard
)))))
847 (setq shifted-num
(ash shifted-num -
1))
850 (defun decimalsin (x)
851 (do ((i (quotient (* 59. x
) 196.
) (1+ i
))) ;log[10](2)=.301029
853 (when (> (integer-length (expt 10. i
)) x
)
856 (defun atanbigfloat (x)
857 (*fpatan
(car x
) (cdr x
)))
860 (fpend (let ((fpprec (+ 8. fpprec
)))
862 (if ($bfloatp a
) (fpatan (cdr ($bfloat a
)))
864 (fpatan2 (cdr ($bfloat a
)) (cdr ($bfloat
(car y
))))))))
868 (prog (term x2 ans oans one two tmp
)
869 (setq one
(intofp 1) two
(intofp 2))
870 (cond ((fpgreaterp (fpabs x
) one
)
874 ;; atan(x) + acot(x) = +/- pi/2 (+ for x >= 0, - for x < 0)
877 ;; acot(z) = atan(1/z)
878 (setq tmp
(fpquotient (fppi) two
))
879 (setq ans
(fpdifference tmp
(fpatan (fpquotient one x
))))
880 (return (cond ((fplessp x
(intofp 0))
881 (fpdifference ans
(fppi)))
883 ((fpgreaterp (fpabs x
) (fpquotient one two
))
886 ;; Use A&S 4.4.42, third formula:
888 ;; atan(z) = z/(1+z^2)*[1 + 2/3*r + (2*4)/(3*5)*r^2 + ...]
891 (setq tmp
(fpquotient x
(fpplus (fptimes* x x
) one
)))
892 (setq x2
(fptimes* x tmp
) term
(setq ans one
))
896 (fptimes* term
(fptimes* x2
(fpquotient
897 (intofp (+ 2 (* 2 n
)))
898 (intofp (+ (* 2 n
) 3))))))
899 (setq oans ans ans
(fpplus term ans
)))
900 (setq ans
(fptimes* tmp ans
)))
902 ;; |x| <= 1/2. Use Taylor series (A&S 4.4.42, first
905 ;; The n'th term is (-1)^n*x^(2*n+1)/(2*n+1). We want to
906 ;; stop summing when the relative error between the n'th
907 ;; term and the first is small. That is
908 ;; |x^(2*n+1)/(2*n+1)/x| <= tol. Hence, |x^(2*n)|/(2*n+1)
909 ;; <= tol. Or |x^(2*n)| <= tol. But we know |x| <= 1/2,
910 ;; so (1/2)^(2*n) <= tol. Then n = -log2(tol)/2. Since
911 ;; tol is basically 2^(-fpprec), n = fpprec/2. But double
912 ;; it so that the testsuite passes without differences.
913 (setq ans x x2
(fpminus (fptimes* x x
)) term x
)
914 (let ((max-n fpprec
))
916 ((or (equal ans oans
)
920 (format t
"n max-n ~A ~A~%" n max-n
)
921 (format t
"ans oans = ~A ~A~%" ans oans
)))
922 (setq term
(fptimes* term x2
))
924 ans
(fpplus ans
(fpquotient term
(intofp n
))))))))
927 (defun big-float-atan (x &optional y
)
928 "Compute atan(x+%i*y) when X and Y are bigfloat objects. Y is optional."
930 ;; atan(z) = -i*atanh(i*z)
931 (multiple-value-bind (u v
)
932 (complex-atanh (neg y
) x
)
933 ;; -%i*(u+%i*v) = v - %i*u
937 (bcons (fpatan (cdr x
))))))
939 ;; atan(y/x) taking into account the quadrant. (Also equal to
942 (cond ((equal (car x
) 0)
943 ;; atan(y/0) = atan(inf), but what sign?
944 (cond ((equal (car y
) 0)
945 (merror (intl:gettext
"atan2: atan2(0, 0) is undefined.")))
947 ;; We're on the negative imaginary axis, so -pi/2.
948 (fpquotient (fppi) (intofp -
2)))
950 ;; The positive imaginary axis, so +pi/2
951 (fpquotient (fppi) (intofp 2)))))
953 ;; x > 0. atan(y/x) is the correct value.
954 (fpatan (fpquotient y x
)))
956 ;; x < 0, and y > 0. We're in quadrant II, so the angle we
957 ;; want is pi+atan(y/x).
958 (fpplus (fppi) (fpatan (fpquotient y x
))))
960 ;; x <= 0 and y <= 0. We're in quadrant III, so the angle we
961 ;; want is atan(y/x)-pi.
962 (fpdifference (fpatan (fpquotient y x
)) (fppi)))))
964 (defun tanbigfloat (a)
966 (fpend (let ((fpprec (+ 8. fpprec
)))
968 (setq a
(cdr ($bfloat a
)))
969 (fpquotient (fpsin a t
) (fpsin a nil
)))
970 (t (list '(%tan
) a
))))))
972 ;; Returns a list of a mantissa and an exponent. This function MUST
973 ;; recognize any symbol in *builtin-numeric-constants* and compute a
974 ;; bfloat value for it.
976 (cond ((not (atom l
))
993 (list (fpround l
) (+ *m fpprec
)))))
995 ;; It seems to me that this function gets called on an integer
996 ;; and returns the mantissa portion of the mantissa/exponent pair.
998 ;; "STICKY BIT" CALCULATION FIXED 10/14/75 --RJF
999 ;; BASE must not get temporarily bound to NIL by being placed
1000 ;; in a PROG list as this will confuse stepping programs.
1002 (defun fpround (l &aux
(*print-base
* 10.
) *print-radix
*)
1006 ;;*M will be positive if the precision of the argument is greater than
1007 ;;the current precision being used.
1008 (setq *m
(- (integer-length l
) fpprec
))
1012 ;;FPSHIFT is essentially LSH.
1013 (setq adjust
(fpshift 1 (1- *m
)))
1014 (when (minusp l
) (setq adjust
(- adjust
)))
1016 (setq *m
(- (integer-length l
) fpprec
))
1017 (setq *cancelled
(abs *m
))
1018 (cond ((zerop (hipart l
(- *m
)))
1019 ;ONLY ZEROES SHIFTED OFF
1020 (return (fpshift (fpshift l
(- -
1 *m
))
1021 1))) ; ROUND TO MAKE EVEN
1022 (t (return (fpshift l
(- *m
))))))
1024 (setq *m
(- (flatsize (abs l
)) fpprec
))
1025 (setq adjust
(fpshift 1 (1- *m
)))
1026 (when (minusp l
) (setq adjust
(- adjust
)))
1027 (setq adjust
(* 5 adjust
))
1028 (setq *m
(- (flatsize (abs (setq l
(+ l adjust
)))) fpprec
))
1029 (return (fpshift l
(- *m
)))))))
1031 ;; Compute (* L (expt d n)) where D is 2 or 10 depending on
1032 ;; *decfp. Throw away an fractional part by truncating to zero.
1033 (defun fpshift (l n
)
1034 (cond ((null *decfp
)
1035 (cond ((and (minusp n
) (minusp l
))
1036 ;; Left shift of negative number requires some
1037 ;; care. (That is, (truncate l (expt 2 n)), but use
1045 (quotient l
(expt 10.
(- n
))))
1048 ;; Bignum LSH -- N is assumed (and declared above) to be a fixnum.
1049 ;; This isn't really LSH, since the sign bit isn't propagated when
1050 ;; shifting to the right, i.e. (BIGLSH -100 -3) = -40, whereas
1051 ;; (LSH -100 -3) = 777777777770 (on a 36 bit machine).
1052 ;; This actually computes (* X (EXPT 2 N)). As of 12/21/80, this function
1053 ;; was only called by FPSHIFT. I would like to hear an argument as why this
1054 ;; is more efficient than simply writing (* X (EXPT 2 N)). Is the
1055 ;; intermediate result created by (EXPT 2 N) the problem? I assume that
1056 ;; EXPT tries to LSH when possible.
1059 (cond ((and (not (bignump x
))
1060 (< n
#.
(- +machine-fixnum-precision
+)))
1062 ;; Either we are shifting a fixnum to the right, or shifting
1063 ;; a fixnum to the left, but not far enough left for it to become
1065 ((and (not (bignump x
))
1067 (< (+ (integer-length x
) n
) #.
+machine-fixnum-precision
+)))
1068 ;; The form which follows is nearly identical to (ASH X N), however
1069 ;; (ASH -100 -20) = -1, whereas (BIGLSH -100 -20) = 0.
1072 (- (biglsh (- x
) n
)))) ;(- x) may be a bignum even is x is a fixnum.
1073 ;; If we get here, then either X is a bignum or our answer is
1074 ;; going to be a bignum.
1076 (cond ((> (abs n
) (integer-length x
)) 0)
1078 (hipart x
(+ (integer-length x
) n
)))
1079 (t (- (hipart x
(+ (integer-length x
) n
))))))
1081 ;; Isn't this the kind of optimization that compilers are
1082 ;; supposed to make?
1083 ((< n
#.
(1- +machine-fixnum-precision
+)) (* x
(ash 1 n
)))
1084 (t (* x
(expt 2 n
)))))
1089 ;; For negative x, use exp(-x) = 1/exp(x)
1091 ;; For x > 0, exp(x) = exp(r+y) = exp(r) * exp(y), where x = r + y and
1095 (unless (signp ge
(car x
))
1096 (return (fpquotient (fpone) (fpexp (fpabs x
)))))
1097 (setq r
(fpintpart x
:skip-exponent-check-p t
))
1098 (return (cond ((< r
2)
1101 (setq s
(fpexp1 (fpdifference x
(intofp r
))))
1104 (let ((fpprec (+ fpprec
(integer-length r
) -
1))
1106 (bcons (fpexpt (fpe) r
))))))))))) ; patch for full precision %E
1108 ;; exp(x) for small x, using Taylor series.
1110 (prog (term ans oans
)
1111 (setq ans
(setq term
(fpone)))
1114 (setq term
(fpquotient (fptimes* x term
) (intofp n
)))
1116 (setq ans
(fpplus ans term
)))
1119 ;; Does one higher precision to round correctly.
1120 ;; A and B are each a list of a mantissa and an exponent.
1121 (defun fpquotient (a b
)
1122 (cond ((equal (car b
) 0)
1123 (merror (intl:gettext
"pquotient: attempted quotient by zero.")))
1124 ((equal (car a
) 0) '(0 0))
1125 (t (list (fpround (quotient (fpshift (car a
) (+ 3 fpprec
)) (car b
)))
1126 (+ -
3 (- (cadr a
) (cadr b
)) *m
)))))
1128 (defun fpgreaterp (a b
)
1129 (fpposp (fpdifference a b
)))
1131 (defun fplessp (a b
)
1132 (fpposp (fpdifference b a
)))
1137 (defun fpmin (arg1 &rest args
)
1139 (mapc #'(lambda (u) (if (fplessp u min
) (setq min u
))) args
)
1142 (defun fpmax (arg1 &rest args
)
1144 (mapc #'(lambda (u) (if (fpgreaterp u max
) (setq max u
))) args
)
1147 ;; The following functions compute bigfloat values for %e, %pi,
1148 ;; %gamma, and log(2). For each precision, the computed value is
1149 ;; cached in a hash table so it doesn't need to be computed again.
1150 ;; There are functions to return the hash table or clear the hash
1151 ;; table, for debugging.
1153 ;; Note that each of these return a bigfloat number, but without the
1157 ;; https://sourceforge.net/p/maxima/bugs/1842/
1158 ;; for an explanation.
1160 ((memoize (name compute-form
)
1161 ;; Macro creates a closure over a hash table containing the
1162 ;; bigfloat values of a constant. The key of the hash table is
1163 ;; the number of bits of precision of the bigfloat. This keeps
1164 ;; Maxima from constantly computing the numeric value of a
1165 ;; constant. Once computed for a certain precision, we can
1166 ;; just look up precomputed value.
1168 ;; A function with the name NAME is created that looks up the
1169 ;; value in hash table. If it exists, return it. If not
1170 ;; update the hash table with a new value computed via
1171 ;; COMPUTE-FORM. This value is returned.
1173 ;; For debugging, we define a function to get the hash table
1174 ;; and a function to clear the hash table of all entries.
1175 (let ((table-getter-name
1176 (intern (concatenate 'string
(string name
) "-TABLE")))
1178 (intern (concatenate 'string
1179 "CLEAR_" (string name
) "_TABLE")))
1180 (table-name (gensym (concatenate 'string
"TABLE-" (string name
)))))
1181 `(let ((,table-name
(make-hash-table)))
1183 (let ((value (gethash fpprec
,table-name
)))
1186 (setf (gethash fpprec
,table-name
) ,compute-form
))))
1187 (defun ,table-getter-name
()
1189 (defun ,table-clearer-name
()
1190 (clrhash ,table-name
))))))
1191 (memoize fpe
(cdr (fpe1)))
1192 (memoize fppi
(cdr (fppi1)))
1193 (memoize fpgamma
(cdr (fpgamma1)))
1194 (memoize fplog2
(comp-log2))
1195 (memoize fpcatalan
(cdr (fpcatalan1)))
1196 (memoize fpphi
(cdr (fpphi1))))
1198 ;; This doesn't need a hash table because there's never a problem with
1199 ;; using a high precision value and rounding to a lower precision
1200 ;; value because 1 is always an exact bfloat.
1202 (cond (*decfp
(intofp 1))
1203 ((= fpprec
(bigfloat-prec bigfloatone
)) (cdr bigfloatone
))
1206 ;;----------------------------------------------------------------------------;;
1208 ;; The values of %e, %pi, %gamma and log(2) are computed by the technique of
1209 ;; binary splitting. See http://www.ginac.de/CLN/binsplit.pdf for details.
1211 ;; Volker van Nek, Sept. 2014
1217 (let ((e (compe (+ fpprec
12)))) ;; compute additional bits
1218 (bcons (list (fpround (car e
)) (cadr e
))) )) ;; round to fpprec
1220 ;; Taylor: %e = sum(s[i] ,i,0,inf) where s[i] = 1/i!
1223 (let ((fpprec prec
))
1224 (multiple-value-bind (tt qq
) (split-taylor-e 0 (taylor-e-size prec
))
1225 (fpquotient (intofp tt
) (intofp qq
)) )))
1227 ;; binary splitting:
1230 ;; s[i] = ----------------------
1231 ;; q[0]*q[1]*q[2]*..*q[i]
1236 (defun split-taylor-e (i j
)
1239 (setq qq
(if (= i
0) 1 i
)
1241 (let ((m (ash (+ i j
) -
1)))
1242 (multiple-value-bind (tl ql
) (split-taylor-e i m
)
1243 (multiple-value-bind (tr qr
) (split-taylor-e m j
)
1245 tt
(+ (* qr tl
) tr
) )))))
1248 ;; stop when i! > 2^fpprec
1250 ;; log(i!) = sum(log(k), k,1,i) > fpprec * log(2)
1252 (defun taylor-e-size (prec)
1254 (lim (* prec
(log 2))) )
1257 (incf acc
(log i
)) )))
1259 ;;----------------------------------------------------------------------------;;
1264 (let ((pi1 (comppi (+ fpprec
10))))
1265 (bcons (list (fpround (car pi1
)) (cadr pi1
))) ))
1267 ;; Chudnovsky & Chudnovsky:
1269 ;; C^(3/2)/(12*%pi) = sum(s[i], i,0,inf),
1271 ;; where s[i] = (-1)^i*(6*i)!*(A*i+B) / (i!^3*(3*i)!*C^(3*i))
1273 ;; and A = 545140134, B = 13591409, C = 640320
1275 (defun comppi (prec)
1277 nr n d oldn tt qq n
*qq
)
1279 ;; compute n/d = sqrt(10005) :
1281 ;; n[0] n[i+1] = n[i]^2+a*d[i]^2 n[inf]
1282 ;; quadratic Heron: x[0] = ----, , sqrt(a) = ------
1283 ;; d[0] d[i+1] = 2*n[i]*d[i] d[inf]
1285 (multiple-value-setq (nr n d
) (sqrt-10005-constants fpprec
))
1288 n
(+ (* n n
) (* 10005 d d
))
1291 ;; divide C^(3/2)/12 = 3335*2^7*sqrt(10005)
1292 ;; by Chudnovsky-sum = tt/qq :
1294 (setq nr
(ceiling (* fpprec
0.021226729578153))) ;; nr of summands
1295 ;; fpprec*log(2)/log(C^3/(24*6*2*6))
1296 (multiple-value-setq (tt qq
) (split-chudnovsky 0 (1+ nr
)))
1298 n
*qq
(intofp (* n qq
)) )
1299 (fpquotient (list (car n
*qq
) (+ (cadr n
*qq
) 7))
1300 (intofp (* d tt
)) )))
1302 ;; The returned n and d serve as start values for the iteration.
1303 ;; n/d = sqrt(10005) with a precision of p = ceiling(prec/2^nr) bits
1304 ;; where nr is the number of needed iterations.
1306 (defun sqrt-10005-constants (prec)
1307 (let (ilen p nr n d
)
1310 (setq ilen
(integer-length prec
)
1312 p
(ceiling (* prec
(expt 2.0 (- nr
)))) ))
1314 ((<= p
76) (setq n
256192036001 d
2561280120))
1315 ((<= p
89) (setq n
51244811200700 d
512320048001))
1316 ((<= p
102) (setq n
2050048640064001 d
20495363200160))
1317 ((<= p
115) (setq n
410060972824000900 d
4099584960080001))
1318 (t (setq n
16404488961600100001 d
164003893766400200)) )
1321 ;; binary splitting:
1323 ;; a[i] * p[0]*p[1]*p[2]*..*p[i]
1324 ;; s[i] = -----------------------------
1325 ;; q[0]*q[1]*q[2]*..*q[i]
1330 ;; p[i] = - (6*i-5)*(2*i-1)*(6*i-1)
1331 ;; q[i] = C^3/24*i^3
1333 (defun split-chudnovsky (i j
)
1334 (let (aa pp
/qq pp qq tt
)
1337 (setq aa
13591409 pp
1 qq
1 tt aa
)
1338 (setq aa
(+ (* i
545140134) 13591409)
1339 pp
/qq
(/ (* (- 5 (* 6 i
)) (- (* 2 i
) 1) (- (* 6 i
) 1))
1340 10939058860032000 ) ; C^3/24
1341 pp
(numerator pp
/qq
)
1342 qq
(* (denominator pp
/qq
) (expt i
3))
1344 (let ((m (ash (+ i j
) -
1)))
1345 (multiple-value-bind (tl ql pl
) (split-chudnovsky i m
)
1346 (multiple-value-bind (tr qr pr
) (split-chudnovsky m j
)
1349 tt
(+ (* qr tl
) (* pl tr
)) )))))
1350 (values tt qq pp
) ))
1352 ;;----------------------------------------------------------------------------;;
1354 ;; Euler-Mascheroni constant GAMMA
1357 (let ((res (comp-bf%gamma
(+ fpprec
14))))
1358 (bcons (list (fpround (car res
)) (cadr res
))) ))
1360 ;; Brent-McMillan algorithm
1363 ;; alpha = 4.970625759544
1365 ;; n > 0 and N-1 >= alpha*n
1367 ;; H(k) = sum(1/i, i,1,k)
1369 ;; S = sum(H(k)*(n^k/k!)^2, k,0,N-1)
1371 ;; I = sum((n^k/k!)^2, k,0,N-1)
1373 ;; T = 1/(4*n)*sum((2*k)!^3/(k!^4*(16*n)^(2*k)), k,0,2*n-1)
1376 ;; %gamma = S/I - T/I^2 - log(n)
1379 ;; |%gamma - gamma| < 24 * e^(-8*n)
1381 ;; (Corollary 2, Remark 2, Brent/Johansson http://arxiv.org/pdf/1312.0039v1.pdf)
1383 (defun comp-bf%gamma
(prec)
1384 (let* ((fpprec prec
)
1385 (n (ceiling (* 1/8 (+ (* prec
(log 2.0)) (log 24.0)))))
1387 (alpha 4.970625759544)
1388 (lim (ceiling (* alpha n
)))
1390 sumi sumi2
;; I and I^2
1391 sumt
/sumi2
) ;; T/I^2
1392 (multiple-value-bind (vv tt qq dd
) (split-gamma-1 1 (1+ lim
) n2
)
1394 ;; sums = vv/(qq*dd)
1396 ;; sums/sumi = vv/(qq*dd)*qq/tt = vv/(dd*tt)
1398 (setq sums
/sumi
(fpquotient (intofp vv
) (intofp (* dd tt
)))
1399 sumi
(fpquotient (intofp tt
) (intofp qq
))
1400 sumi2
(fptimes* sumi sumi
) )
1402 (multiple-value-bind (ttt qqq
) (split-gamma-2 0 (* 2 n
) (* 32 n2
))
1404 ;; sumt = 1/(4*n)*ttt/qqq
1405 ;; sumt/sumi2 = ttt/(4*n*qqq*sumi2)
1407 (setq sumt
/sumi2
(fpquotient (intofp ttt
)
1408 (fptimes* (intofp (* 4 n qqq
)) sumi2
) ))
1410 (fpdifference sums
/sumi
(fpplus sumt
/sumi2
(log-n n
)) )))))
1412 ;; split S and I simultaneously:
1414 ;; summands I[0] = 1, I[i]/I[i-1] = n^2/i^2
1416 ;; S[0] = 0, S[i]/S[i-1] = n^2/i^2*H(i)/H(i-1)
1418 ;; p[0]*p[1]*p[2]*..*p[i]
1419 ;; I[i] = ----------------------
1420 ;; q[0]*q[1]*q[2]*..*q[i]
1426 ;; c[0] c[1] c[2] c[i]
1427 ;; S[i] = H[i] * I[i], where H[i] = ---- + ---- + ---- + .. + ----
1428 ;; d[0] d[1] d[2] d[i]
1434 (defun split-gamma-1 (i j n2
)
1435 (let (pp cc dd qq tt vv
)
1438 (if (= i
1) ;; S[0] is 0 -> start with i=1 and add I[0]=1 to tt :
1439 (setq pp n2 cc
1 dd
1 qq
1 tt
(1+ n2
) vv n2
)
1440 (setq pp n2 cc
1 dd i qq
(* i i
) tt pp vv tt
) ))
1442 (let* ((m (ash (+ i j
) -
1)) tmp
)
1443 (multiple-value-bind (vl tl ql dl cl pl
) (split-gamma-1 i m n2
)
1444 (multiple-value-bind (vr tr qr dr cr pr
) (split-gamma-1 m j n2
)
1446 cc
(+ (* cl dr
) (* dl cr
))
1450 tt
(+ (* tl qr
) tmp
)
1451 vv
(+ (* dr
(+ (* vl qr
) (* cl tmp
))) (* dl pl vr
)) ))))))
1452 (values vv tt qq dd cc pp
) ))
1456 ;; summands T[0] = 1, T[i]/T[i-1] = (2*i-1)^3/(32*i*n^2)
1458 ;; p[0]*p[1]*p[2]*..*p[i]
1459 ;; T[i] = ----------------------
1460 ;; q[0]*q[1]*q[2]*..*q[i]
1462 ;; where p[0] = q[0] = 1
1466 (defun split-gamma-2 (i j n2
*32)
1471 (setq pp
1 qq
1 tt
1)
1472 (setq pp
(expt (1- (* 2 i
)) 3) qq
(* i n2
*32) tt pp
) ))
1474 (let* ((m (ash (+ i j
) -
1)))
1475 (multiple-value-bind (tl ql pl
) (split-gamma-2 i m n2
*32)
1476 (multiple-value-bind (tr qr pr
) (split-gamma-2 m j n2
*32)
1479 tt
(+ (* tl qr
) (* pl tr
)) ))))))
1480 (values tt qq pp
) ))
1482 ;;----------------------------------------------------------------------------;;
1484 ;; log(2) = 18*L(26) - 2*L(4801) + 8*L(8749)
1486 ;; where L(k) = atanh(1/k)
1488 ;; see http://numbers.computation.free.fr/Constants/constants.html
1490 ;;;(defun $log2 () (bcons (comp-log2))) ;; checked against reference table
1494 (let ((fpprec (+ fpprec
12)))
1496 (fpdifference (n*atanh-1
/k
18 26) (n*atanh-1
/k
2 4801))
1497 (n*atanh-1
/k
8 8749) ))))
1498 (list (fpround (car res
)) (cadr res
)) ))
1500 ;; Taylor: atanh(1/k) = sum(s[i], i,0,inf)
1502 ;; where s[i] = 1/((2*i+1)*k^(2*i+1))
1504 (defun n*atanh-1
/k
(n k
) ;; integer n,k
1506 (nr (ceiling (* fpprec
(/ (log 2) (log k2
))))) )
1507 (multiple-value-bind (tt qq bb
) (split-atanh-1/k
0 (1+ nr
) k k2
)
1508 (fpquotient (intofp (* n tt
)) (intofp (* bb qq
))) )))
1510 ;; binary splitting:
1512 ;; s[i] = -----------------------------
1513 ;; b[i] * q[0]*q[1]*q[2]*..*q[i]
1520 (defun split-atanh-1/k
(i j k k2
)
1524 (setq bb
1 qq k tt
1)
1525 (setq bb
(1+ (* 2 i
)) qq k2 tt
1) )
1526 (let ((m (ash (+ i j
) -
1)))
1527 (multiple-value-bind (tl ql bl
) (split-atanh-1/k i m k k2
)
1528 (multiple-value-bind (tr qr br
) (split-atanh-1/k m j k k2
)
1531 tt
(+ (* br qr tl
) (* bl tr
)) )))))
1532 (values tt qq bb
) ))
1534 ;;----------------------------------------------------------------------------;;
1536 ;; log(n) = log(n/2^k) + k*log(2)
1538 ;;;(defun $log10 () (bcons (log-n 10))) ;; checked against reference table
1540 (defun log-n (n) ;; integer n > 0
1542 ((= 1 n
) (list 0 0))
1543 ((= 2 n
) (comp-log2))
1546 (let ((fpprec (+ fpprec
10))
1547 (k (integer-length n
)) )
1548 ;; choose k so that |n/2^k - 1| is as small as possible:
1549 (when (< n
(* (coerce 2/3 'flonum
) (ash 1 k
))) (decf k
))
1550 ;; now |n/2^k - 1| <= 1/3
1551 (fpplus (log-u/2^k n k fpprec
)
1552 (fptimes* (intofp k
) (comp-log2)) ))))
1553 (list (fpround (car res
)) (cadr res
)) ))))
1555 ;; log(1+u/v) = 2 * sum(s[i], i,0,inf)
1557 ;; where s[i] = (u/(2*v+u))^(2*i+1)/(2*i+1)
1559 (defun log-u/2^k
(u k prec
) ;; integer u k; x = u/2^k; |x - 1| < 1
1560 (setq u
(- u
(ash 1 k
))) ;; x <-- x - 1
1562 ((= 0 u
) (list 0 0))
1564 (while (evenp u
) (setq u
(ash u -
1)) (decf k
))
1568 (nr (ceiling (* prec
(/ (log 2) 2 (log (abs (/ w u
)))))))
1570 (multiple-value-bind (tt qq bb
) (split-log-1+u
/v
0 (1+ nr
) u u2 w w2
)
1571 (setq lg
/2 (fpquotient (intofp tt
) (intofp (* bb qq
)))) ;; sum
1572 (list (car lg
/2) (1+ (cadr lg
/2))) ))))) ;; 2*sum
1574 ;; binary splitting:
1576 ;; p[0]*p[1]*p[2]*..*p[i]
1577 ;; s[i] = -----------------------------
1578 ;; b[i] * q[0]*q[1]*q[2]*..*q[i]
1587 (defun split-log-1+u
/v
(i j u u2 w w2
)
1591 (setq pp u bb
1 qq w tt u
)
1592 (setq pp u2 bb
(1+ (* 2 i
)) qq w2 tt pp
) )
1593 (let ((m (ash (+ i j
) -
1)))
1594 (multiple-value-bind (tl ql bl pl
) (split-log-1+u
/v i m u u2 w w2
)
1595 (multiple-value-bind (tr qr br pr
) (split-log-1+u
/v m j u u2 w w2
)
1599 tt
(+ (* br qr tl
) (* bl pl tr
)) )))))
1600 (values tt qq bb pp
) ))
1602 ;;----------------------------------------------------------------------------;;
1603 (defun fpcatalan1 ()
1604 ;; Use 5 extra bits when computing %catalan. Not exactly sure what
1605 ;; is right value, but 5 seems good enough.
1606 (let ((catalan (cdr (bigfloat::comp-catalan
(+ fpprec
5)))))
1607 ;; Round value that has extra bits to the current number of bits
1609 (bcons (list (fpround (car catalan
))
1615 (let* ((phi (let ((fpprec (+ fpprec
2)))
1616 ;; Use couple of extra bits to compute %phi =
1618 (cdr ($bfloat
(div (add 1 (power 5 1//2))
1620 ;; Round value that has extra bits to the current number of bits
1622 (bcons (list (fpround (car phi
))
1626 ;;----------------------------------------------------------------------------;;
1629 (defun fpdifference (a b
)
1630 (fpplus a
(fpminus b
)))
1633 (if (equal (car x
) 0)
1635 (list (- (car x
)) (cadr x
))))
1638 (prog (*m exp man sticky
)
1640 (cond ((equal (car a
) 0) (return b
))
1641 ((equal (car b
) 0) (return a
)))
1642 (setq exp
(- (cadr a
) (cadr b
)))
1643 (setq man
(cond ((equal exp
0)
1645 (fpshift (+ (car a
) (car b
)) 2))
1647 (setq sticky
(hipart (car b
) (- 1 exp
)))
1648 (setq sticky
(cond ((signp e sticky
) 0)
1649 ((signp l
(car b
)) -
1)
1651 ; COMPUTE STICKY BIT
1652 (+ (fpshift (car a
) 2)
1653 ; MAKE ROOM FOR GUARD DIGIT & STICKY BIT
1654 (fpshift (car b
) (- 2 exp
))))
1655 (t (setq sticky
(hipart (car a
) (1+ exp
)))
1656 (setq sticky
(cond ((signp e sticky
) 0)
1657 ((signp l
(car a
)) -
1)
1659 (+ (fpshift (car b
) 2)
1660 (fpshift (car a
) (+ 2 exp
))))))
1661 (setq man
(+ man sticky
))
1662 (return (cond ((equal man
0) '(0 0))
1663 (t (setq man
(fpround man
))
1664 (setq exp
(+ -
2 *m
(max (cadr a
) (cadr b
))))
1667 (defun fptimes* (a b
)
1668 (if (or (zerop (car a
)) (zerop (car b
)))
1670 (list (fpround (* (car a
) (car b
)))
1671 (+ *m
(cadr a
) (cadr b
) (- fpprec
)))))
1673 ;; Don't use the symbol BASE since it is SPECIAL.
1675 (defun fpintexpt (int nn fixprec
) ;INT is integer
1676 (setq fixprec
(truncate fixprec
(1- (integer-length int
)))) ;NN is pos
1677 (let ((bas (intofp (expt int
(min nn fixprec
)))))
1679 (fptimes* (intofp (expt int
(rem nn fixprec
)))
1680 (fpexpt bas
(quotient nn fixprec
)))
1683 ;; NN is positive or negative integer
1685 (defun fpexpt (p nn
)
1686 (cond ((zerop nn
) (fpone))
1688 ((< nn
0) (fpquotient (fpone) (fpexpt p
(- nn
))))
1693 (do ((ii (quotient nn
2) (quotient ii
2)))
1695 (setq p
(fptimes* p p
))
1697 (setq u
(fptimes* u p
))))
1700 (defun exptbigfloat (p n
)
1701 (cond ((equal n
1) p
)
1702 ((equal n
0) ($bfloat
1))
1703 ((not ($bfloatp p
)) (list '(mexpt) p n
))
1704 ((equal (cadr p
) 0) ($bfloat
0))
1705 ((and (< (cadr p
) 0) (ratnump n
))
1706 (mul2 (let ($numer $float $keepfloat $ratprint
)
1708 (exptbigfloat (bcons (fpminus (cdr p
))) n
)))
1709 ((and (< (cadr p
) 0) (not (integerp n
)))
1710 (cond ((or (equal n
0.5) (equal n bfhalf
))
1711 (exptbigfloat p
'((rat simp
) 1 2)))
1712 ((or (equal n -
0.5) (equal n bfmhalf
))
1713 (exptbigfloat p
'((rat simp
) -
1 2)))
1714 (($bfloatp
(setq n
($bfloat n
)))
1715 (cond ((equal n
($bfloat
(fpentier n
)))
1716 (exptbigfloat p
(fpentier n
)))
1717 (t ;; for P<0: P^N = (-P)^N*cos(pi*N) + i*(-P)^N*sin(pi*N)
1718 (setq p
(exptbigfloat (bcons (fpminus (cdr p
))) n
)
1719 n
($bfloat
`((mtimes) $%pi
,n
)))
1720 (add2 ($bfloat
`((mtimes) ,p
,(*fpsin n nil
)))
1721 `((mtimes simp
) ,($bfloat
`((mtimes) ,p
,(*fpsin n t
)))
1723 (t (list '(mexpt) p n
))))
1724 ((and (ratnump n
) (< (caddr n
) 10.
))
1725 (bcons (fpexpt (fproot p
(caddr n
)) (cadr n
))))
1727 (setq n
($bfloat n
))
1729 ((not ($bfloatp n
)) (list '(mexpt) p n
))
1731 (let ((extrabits (max 1 (+ (caddr n
) (integer-length (caddr p
))))))
1733 (let ((fpprec (+ extrabits fpprec
)))
1734 (fpexp (fptimes* (cdr (bigfloatp n
)) (fplog (cdr (bigfloatp p
)))))))
1735 (setq p
(list (fpround (car p
)) (+ (- extrabits
) *m
(cadr p
))))
1737 ;; The number of extra bits required
1738 ((< n
0) (invertbigfloat (exptbigfloat p
(- n
))))
1739 (t (bcons (fpexpt (cdr p
) n
)))))
1741 (defun fproot (a n
) ; computes a^(1/n) see Fitch, SIGSAM Bull Nov 74
1743 ;; Special case for a = 0b0. General algorithm loops endlessly in that case.
1745 ;; Unlike many or maybe all of the other functions named FP-something,
1746 ;; FPROOT assumes it is called with an argument like
1747 ;; '((BIGFLOAT ...) FOO BAR) instead of '(FOO BAR).
1748 ;; However FPROOT does return something like '(FOO BAR).
1750 (if (eql (cadr a
) 0)
1753 (let* ((ofprec fpprec
)
1754 (fpprec (+ fpprec
2)) ;assumes a>0 n>=2
1755 (bk (fpexpt (intofp 2) (1+ (quotient (cadr (setq a
(cdr (bigfloatp a
)))) n
)))))
1756 (do ((x bk
(fpdifference x
1757 (setq bk
(fpquotient (fpdifference
1758 x
(fpquotient a
(fpexpt x n1
))) n
))))
1761 ((or (equal bk
'(0 0))
1762 (> (- (cadr x
) (cadr bk
)) ofprec
))
1764 (list (fpround (car a
)) (+ -
2 *m
(cadr a
))))))
1766 (defun timesbigfloat (h)
1767 (prog (fans r nfans
)
1768 (setq fans
(bcons (fpone)) nfans
1)
1771 (if (setq r
(bigfloatp (car l
)))
1772 (setq fans
(bcons (fptimes* (cdr r
) (cdr fans
))))
1773 (setq nfans
(list '(mtimes) (car l
) nfans
))))
1774 (return (if (equal nfans
1)
1776 (simplify (list '(mtimes) fans nfans
))))))
1778 (defun invertbigfloat (a)
1779 ;; If A is a bigfloat, be sure to round it to the current precision.
1780 ;; (See Bug 2543079 for one of the symptoms.)
1781 (let ((b (bigfloatp a
)))
1783 (bcons (fpquotient (fpone) (cdr b
)))
1784 (simplify (list '(mexpt) a -
1)))))
1787 (fpend (let ((fpprec (+ 8. fpprec
)))
1789 (fpexp (cdr (bigfloatp a
)))
1790 (list '(mexpt) '$%e a
)))))
1792 (defun *fpsin
(a fl
)
1793 (fpend (let ((fpprec (+ 8. fpprec
)))
1794 (cond (($bfloatp a
) (fpsin (cdr ($bfloat a
)) fl
))
1795 (fl (list '(%sin
) a
))
1796 (t (list '(%cos
) a
))))))
1799 (cond ((equal (car a
) 0) (bcons a
))
1801 (setq a
(list (fpround (car a
)) (+ -
8.
*m
(cadr a
))))
1805 (defun fparcsimp (e) ; needed for e.g. ASIN(.123567812345678B0) with
1806 ;; FPPREC 16, to get rid of the minuscule imaginary
1807 ;; part of the a+bi answer.
1808 (if (and (mplusp e
) (null (cdddr e
))
1809 (mtimesp (caddr e
)) (null (cdddr (caddr e
)))
1810 ($bfloatp
(cadr (caddr e
)))
1811 (eq (caddr (caddr e
)) '$%i
)
1812 (< (caddr (cadr (caddr e
))) (+ (- fpprec
) 2)))
1816 (defun sinbigfloat (x)
1819 (defun cosbigfloat (x)
1820 (*fpsin
(car x
) nil
))
1822 ;; THIS VERSION OF FPSIN COMPUTES SIN OR COS TO PRECISION FPPREC,
1823 ;; BUT CHECKS FOR THE POSSIBILITY OF CATASTROPHIC CANCELLATION DURING
1824 ;; ARGUMENT REDUCTION (E.G. SIN(N*%PI+EPSILON))
1825 ;; *FPSINCHECK* WILL CAUSE PRINTOUT OF ADDITIONAL INFO WHEN
1826 ;; EXTRA PRECISION IS NEEDED FOR SIN/COS CALCULATION. KNOWN
1827 ;; BAD FEATURES: IT IS NOT NECESSARY TO USE EXTRA PRECISION FOR, E.G.
1828 ;; SIN(PI/2), WHICH IS NOT NEAR ZERO, BUT EXTRA
1829 ;; PRECISION IS USED SINCE IT IS NEEDED FOR COS(PI/2).
1830 ;; PRECISION SEEMS TO BE 100% SATISFACTORY FOR LARGE ARGUMENTS, E.G.
1831 ;; SIN(31415926.0B0), BUT LESS SO FOR SIN(3.1415926B0). EXPLANATION
1832 ;; NOT KNOWN. (9/12/75 RJF)
1834 (defvar *fpsincheck
* nil
)
1836 ;; FL is a T for sin and NIL for cos.
1838 (prog (piby2 r sign res k
*cancelled
)
1839 (setq sign
(cond (fl (signp g
(car x
)))
1842 (when (equal (car x
) 0)
1843 (return (if fl
(intofp 0) (intofp 1))))
1847 (let ((fpprec (max fpprec
(+ fpprec
(cadr x
))))
1852 loop
(setq x
(cdr (bigfloatp xt
)))
1853 (setq piby2
(fpquotient (fppi) (intofp 2)))
1854 (setq r
(fpintpart (fpquotient x piby2
) :skip-exponent-check-p t
))
1855 (setq x
(fpplus x
(fptimes* (intofp (- r
)) piby2
)))
1857 (fpplus x
(fpminus piby2
))
1858 (setq *cancelled
(max k
*cancelled
))
1860 (print `(*canc
= ,*cancelled fpprec
= ,fpprec oldprec
= ,oldprec
)))
1861 (cond ((not (> oldprec
(- fpprec
*cancelled
)))
1864 (cond (fl (cond ((= r
0) (fpsin1 x
))
1865 ((= r
1) (fpcos1 x
))
1866 ((= r
2) (fpminus (fpsin1 x
)))
1867 ((= r
3) (fpminus (fpcos1 x
)))))
1868 (t (cond ((= r
0) (fpcos1 x
))
1869 ((= r
1) (fpminus (fpsin1 x
)))
1870 ((= r
2) (fpminus (fpcos1 x
)))
1871 ((= r
3) (fpsin1 x
))))))
1872 (return (bcons (if sign res
(fpminus res
)))))
1874 (incf fpprec
*cancelled
)
1880 ;; Compute SIN or COS in (0,PI/2). FL is T for SIN, NIL for COS.
1882 ;; Use Taylor series
1883 (defun fpsincos1 (x fl
)
1884 (prog (ans term oans x2
)
1885 (setq ans
(if fl x
(intofp 1))
1886 x2
(fpminus(fptimes* x x
)))
1888 (do ((n (if fl
3 2) (+ n
2)))
1890 (setq term
(fptimes* term
(fpquotient x2
(intofp (* n
(1- n
))))))
1892 ans
(fpplus ans term
)))
1899 (if (signp ge
(car x
))
1901 (cons (- (car x
)) (cdr x
))))
1904 (let ((fpprec (bigfloat-prec f
)))
1905 (fpintpart (cdr f
))))
1907 ;; Calculate the integer part of a floating point number that is represented as
1910 ;; (MANTISSA EXPONENT)
1912 ;; The special variable fpprec should be bound to the precision (in bits) of the
1913 ;; number. This encodes how many bits are known of the result and also a right
1914 ;; shift. The pair denotes the number MANTISSA * 2^(EXPONENT - FPPREC), of which
1915 ;; FPPREC bits are known.
1917 ;; If EXPONENT is large and positive then we might not have enough
1918 ;; information to calculate the integer part. Specifically, we only
1919 ;; have enough information if EXPONENT < FPPREC. If that isn't the
1920 ;; case, we signal a Maxima error. However, if SKIP-EXPONENT-CHECK-P
1921 ;; is non-NIL, this check is skipped, and we compute the integer part
1924 ;; For the bigfloat code here, skip-exponent-check-p should be true.
1925 ;; For other uses (see commit 576c7508 and bug #2784), this should be
1926 ;; nil, which is the default.
1927 (defun fpintpart (f &key skip-exponent-check-p
)
1928 (destructuring-bind (mantissa exponent
)
1930 (let ((m (- fpprec exponent
)))
1932 (quotient mantissa
(expt 2 (- fpprec exponent
)))
1933 (if (and (not skip-exponent-check-p
) (< exponent fpprec
))
1934 (merror "~M doesn't have enough precision to compute its integer part"
1935 `((bigfloat ,fpprec
) ,mantissa
,exponent
))
1936 (* mantissa
(expt 2 (- m
))))))))
1938 (defun logbigfloat (a)
1939 (cond (($bfloatp
(car a
))
1940 (big-float-log ($bfloat
(car a
))))
1942 (list '(%log
) (car a
)))))
1945 ;;; Computes the log of a bigfloat number.
1949 ;;; log(1+x) = sum((x/(x+2))^(2*n+1)/(2*n+1),n,0,inf);
1955 ;;; = 2 > --------------
1961 ;;; which converges for x > 0.
1963 ;;; Note that FPLOG is given 1+X, not X.
1965 ;;; However, to aid convergence of the series, we scale 1+x until 1/e
1969 (prog (over two ans oldans term e sum
)
1970 (unless (> (car x
) 0)
1971 (merror (intl:gettext
"fplog: argument must be positive; found: ~M") (car x
)))
1973 over
(fpquotient (fpone) e
)
1975 ;; Scale X until 1/e < X <= E. ANS keeps track of how
1976 ;; many factors of E were used. Set X to NIL if X is E.
1979 (cond ((equal x e
) (setq x nil
) (return nil
))
1980 ((and (fplessp x e
) (fplessp over x
))
1983 (setq x
(fptimes* x e
))
1987 (setq x
(fpquotient x e
)))))
1988 (when (null x
) (return (intofp (1+ ans
))))
1989 ;; Prepare X for the series. The series is for 1 + x, so
1990 ;; get x from our X. TERM is (x/(x+2)). X becomes
1992 (setq x
(fpdifference x
(fpone))
1994 (setq x
(fpexpt (setq term
(fpquotient x
(fpplus x
(setq two
(intofp 2))))) 2))
1995 ;; Sum the series until the sum (in ANS) doesn't change
1997 (setq sum
(intofp 0))
1999 ((equal sum oldans
))
2001 (setq sum
(fpplus sum
(fpquotient term
(intofp n
))))
2002 (setq term
(fptimes* term x
)))
2003 (return (fpplus ans
(fptimes* two sum
)))))
2005 (defun mabsbigfloat (l)
2007 (setq r
(bigfloatp (car l
)))
2008 (return (if (null r
)
2009 (list '(mabs) (car l
))
2010 (bcons (fpabs (cdr r
)))))))
2013 ;;;; Bigfloat implementations of special functions.
2016 ;;; This is still a bit messy. Some functions here take bigfloat
2017 ;;; numbers, represented by ((bigfloat) <mant> <exp>), but others want
2018 ;;; just the FP number, represented by (<mant> <exp>). Likewise, some
2019 ;;; return a bigfloat, some return just the FP.
2021 ;;; This needs to be systemized somehow. It isn't helped by the fact
2022 ;;; that some of the routines above also do the samething.
2024 ;;; The implementation for the special functions for a complex
2025 ;;; argument are mostly taken from W. Kahan, "Branch Cuts for Complex
2026 ;;; Elementary Functions or Much Ado About Nothing's Sign Bit", in
2027 ;;; Iserles and Powell (eds.) "The State of the Art in Numerical
2028 ;;; Analysis", pp 165-211, Clarendon Press, 1987
2030 ;; Compute exp(x) - 1, but do it carefully to preserve precision when
2031 ;; |x| is small. X is a FP number, and a FP number is returned. That
2032 ;; is, no bigfloat stuff.
2034 ;; What is the right breakpoint here? Is 1 ok? Perhaps 1/e is better?
2035 (cond ((fpgreaterp (fpabs x
) (fpone))
2037 (fpdifference (fpexp x
) (fpone)))
2039 ;; Use Taylor series for exp(x) - 1
2045 (setf term
(fpquotient (fptimes* x term
) (intofp n
)))
2047 (setf ans
(fpplus ans term
)))
2050 ;; log(1+x) for small x. X is FP number, and a FP number is returned.
2052 ;; Use the same series as given above for fplog. For small x we use
2053 ;; the series, otherwise fplog is accurate enough.
2054 (cond ((fpgreaterp (fpabs x
) (fpone))
2055 (fplog (fpplus x
(fpone))))
2057 (let* ((sum (intofp 0))
2058 (term (fpquotient x
(fpplus x
(intofp 2))))
2059 (f (fptimes* term term
))
2062 ((equal sum oldans
))
2064 (setq sum
(fpplus sum
(fpquotient term
(intofp n
))))
2065 (setq term
(fptimes* term f
)))
2066 (fptimes* sum
(intofp 2))))))
2068 ;; sinh(x) for real x. X is a bigfloat, and a bigfloat is returned.
2070 ;; X must be a maxima bigfloat
2072 ;; See, for example, Hart et al., Computer Approximations, 6.2.27:
2074 ;; sinh(x) = 1/2*(D(x) + D(x)/(1+D(x)))
2076 ;; where D(x) = exp(x) - 1.
2078 ;; But for negative x, use sinh(x) = -sinh(-x) because D(x)
2079 ;; approaches -1 for large negative x.
2080 (cond ((equal 0 (cadr x
))
2081 ;; Special case: x=0. Return immediately.
2085 (let ((d (fpexpm1 (cdr (bigfloatp x
)))))
2086 (bcons (fpquotient (fpplus d
(fpquotient d
(fpplus d
(fpone))))
2091 (fpminus (cdr (fpsinh (bcons (fpminus (cdr (bigfloatp x
)))))))))))
2093 (defun big-float-sinh (x &optional y
)
2094 ;; The rectform for sinh for complex args should be numerically
2095 ;; accurate, so return nil in that case.
2099 ;; asinh(x) for real x. X is a bigfloat, and a bigfloat is returned.
2101 ;; asinh(x) = sign(x) * log(|x| + sqrt(1+x*x))
2105 ;; asinh(x) = x, if 1+x*x = 1
2106 ;; = sign(x) * (log(2) + log(x)), large |x|
2107 ;; = sign(x) * log(2*|x| + 1/(|x|+sqrt(1+x*x))), if |x| > 2
2108 ;; = sign(x) * log1p(|x|+x^2/(1+sqrt(1+x*x))), otherwise.
2110 ;; But I'm lazy right now and we only implement the last 2 cases.
2111 ;; We should implement all cases.
2112 (let* ((fp-x (cdr (bigfloatp x
)))
2116 (minus (minusp (car fp-x
)))
2118 ;; We only use two formulas here. |x| <= 2 and |x| > 2. Should
2119 ;; we add one for very big x and one for very small x, as given above.
2120 (cond ((fpgreaterp absx two
)
2123 ;; log(2*|x| + 1/(|x|+sqrt(1+x^2)))
2124 (setf result
(fplog (fpplus (fptimes* absx two
)
2127 (fproot (bcons (fpplus one
2128 (fptimes* absx absx
)))
2133 ;; log1p(|x|+x^2/(1+sqrt(1+x^2)))
2134 (let ((x*x
(fptimes* absx absx
)))
2135 (setq result
(fplog1p (fpplus absx
2138 (fproot (bcons (fpplus one x
*x
))
2141 (bcons (fpminus result
))
2144 (defun complex-asinh (x y
)
2145 ;; asinh(z) = -%i * asin(%i*z)
2146 (multiple-value-bind (u v
)
2147 (complex-asin (mul -
1 y
) x
)
2148 (values v
(bcons (fpminus (cdr u
))))))
2150 (defun big-float-asinh (x &optional y
)
2152 (multiple-value-bind (u v
)
2154 (add u
(mul '$%i v
)))
2157 (defun fpasin-core (x)
2158 ;; asin(x) = atan(x/(sqrt(1-x^2))
2159 ;; = sgn(x)*[%pi/2 - atan(sqrt(1-x^2)/abs(x))]
2161 ;; Use the first for 0 <= x < 1/2 and the latter for 1/2 < x <= 1.
2163 ;; If |x| > 1, we need to do something else.
2165 ;; asin(x) = -%i*log(sqrt(1-x^2)+%i*x)
2166 ;; = -%i*log(%i*x + %i*sqrt(x^2-1))
2167 ;; = -%i*[log(|x + sqrt(x^2-1)|) + %i*%pi/2]
2168 ;; = %pi/2 - %i*log(|x+sqrt(x^2-1)|)
2170 (let ((fp-x (cdr (bigfloatp x
))))
2171 (cond ((minusp (car fp-x
))
2172 ;; asin(-x) = -asin(x);
2173 (mul -
1 (fpasin (bcons (fpminus fp-x
)))))
2174 ((fplessp fp-x
(cdr bfhalf
))
2176 ;; asin(x) = atan(x/sqrt(1-x^2))
2178 (fpatan (fpquotient fp-x
2180 (fptimes* (fpdifference (fpone) fp-x
)
2181 (fpplus (fpone) fp-x
)))
2183 ((fpgreaterp fp-x
(fpone))
2185 ;; asin(x) = %pi/2 - %i*log(|x+sqrt(x^2-1)|)
2187 ;; Should we try to do something a little fancier with the
2188 ;; argument to log and use log1p for better accuracy?
2189 (let ((arg (fpplus fp-x
2190 (fproot (bcons (fptimes* (fpdifference fp-x
(fpone))
2191 (fpplus fp-x
(fpone))))
2194 (mul -
1 '$%i
(bcons (fplog arg
))))))
2198 ;; asin(x) = %pi/2 - atan(sqrt(1-x^2)/x)
2203 (fpquotient (fproot (bcons (fptimes* (fpdifference (fpone) fp-x
)
2204 (fpplus (fpone) fp-x
)))
2208 ;; asin(x) for real x. X is a bigfloat, and a maxima number (real or
2209 ;; complex) is returned.
2211 ;; asin(x) = atan(x/(sqrt(1-x^2))
2212 ;; = sgn(x)*[%pi/2 - atan(sqrt(1-x^2)/abs(x))]
2214 ;; Use the first for 0 <= x < 1/2 and the latter for 1/2 < x <= 1.
2216 ;; If |x| > 1, we need to do something else.
2218 ;; asin(x) = -%i*log(sqrt(1-x^2)+%i*x)
2219 ;; = -%i*log(%i*x + %i*sqrt(x^2-1))
2220 ;; = -%i*[log(|x + sqrt(x^2-1)|) + %i*%pi/2]
2221 ;; = %pi/2 - %i*log(|x+sqrt(x^2-1)|)
2223 ($bfloat
(fpasin-core x
)))
2225 ;; Square root of a complex number (xx, yy). Both are bigfloats. FP
2226 ;; (non-bigfloat) numbers are returned.
2227 (defun complex-sqrt (xx yy
)
2228 (let* ((x (cdr (bigfloatp xx
)))
2229 (y (cdr (bigfloatp yy
)))
2230 (rho (fpplus (fptimes* x x
)
2232 (setf rho
(fpplus (fpabs x
) (fproot (bcons rho
) 2)))
2233 (setf rho
(fpplus rho rho
))
2234 (setf rho
(fpquotient (fproot (bcons rho
) 2) (intofp 2)))
2238 (when (fpgreaterp rho
(intofp 0))
2239 (setf nu
(fpquotient (fpquotient nu rho
) (intofp 2)))
2240 (when (fplessp x
(intofp 0))
2241 (setf eta
(fpabs nu
))
2242 (setf nu
(if (minusp (car y
))
2247 ;; asin(z) for complex z = x + %i*y. X and Y are bigfloats. The real
2248 ;; and imaginary parts are returned as bigfloat numbers.
2249 (defun complex-asin (x y
)
2250 (let ((x (cdr (bigfloatp x
)))
2251 (y (cdr (bigfloatp y
))))
2252 (multiple-value-bind (re-sqrt-1-z im-sqrt-1-z
)
2253 (complex-sqrt (bcons (fpdifference (intofp 1) x
))
2254 (bcons (fpminus y
)))
2255 (multiple-value-bind (re-sqrt-1+z im-sqrt-1
+z
)
2256 (complex-sqrt (bcons (fpplus (intofp 1) x
))
2258 ;; Realpart is atan(x/Re(sqrt(1-z)*sqrt(1+z)))
2259 ;; Imagpart is asinh(Im(conj(sqrt(1-z))*sqrt(1+z)))
2261 (let ((d (fpdifference (fptimes* re-sqrt-1-z
2263 (fptimes* im-sqrt-1-z
2265 ;; Check for division by zero. If we would divide
2266 ;; by zero, return pi/2 or -pi/2 according to the
2268 (cond ((equal d
'(0 0))
2269 (if (fplessp x
'(0 0))
2270 (fpminus (fpquotient (fppi) (intofp 2)))
2271 (fpquotient (fppi) (intofp 2))))
2273 (fpatan (fpquotient x d
))))))
2275 (fpdifference (fptimes* re-sqrt-1-z
2277 (fptimes* im-sqrt-1-z
2278 re-sqrt-1
+z
)))))))))
2280 (defun big-float-asin (x &optional y
)
2282 (multiple-value-bind (u v
) (complex-asin x y
)
2283 (add u
(mul '$%i v
)))
2287 ;; tanh(x) for real x. X is a bigfloat, and a bigfloat is returned.
2289 ;; X is Maxima bigfloat
2290 ;; tanh(x) = D(2*x)/(2+D(2*x))
2291 (let* ((two (intofp 2))
2292 (fp (cdr (bigfloatp x
)))
2293 (d (fpexpm1 (fptimes* fp two
))))
2294 (bcons (fpquotient d
(fpplus d two
)))))
2296 ;; tanh(z), z = x + %i*y. X, Y are bigfloats, and a maxima number is
2298 (defun complex-tanh (x y
)
2299 (let* ((tv (cdr (tanbigfloat (list y
))))
2300 (beta (fpplus (fpone) (fptimes* tv tv
)))
2301 (s (cdr (fpsinh x
)))
2302 (s^
2 (fptimes* s s
))
2303 (rho (fproot (bcons (fpplus (fpone) s^
2)) 2))
2304 (den (fpplus (fpone) (fptimes* beta s^
2))))
2305 (values (bcons (fpquotient (fptimes* beta
(fptimes* rho s
)) den
))
2306 (bcons (fpquotient tv den
)))))
2308 (defun big-float-tanh (x &optional y
)
2310 (multiple-value-bind (u v
) (complex-tanh x y
)
2311 (add u
(mul '$%i v
)))
2314 ;; atanh(x) for real x, |x| <= 1. X is a bigfloat, and a bigfloat is
2317 ;; atanh(x) = -atanh(-x)
2318 ;; = 1/2*log1p(2*x/(1-x)), x >= 0.5
2319 ;; = 1/2*log1p(2*x+2*x*x/(1-x)), x <= 0.5
2321 (let* ((fp-x (cdr (bigfloatp x
))))
2322 (cond ((fplessp fp-x
(intofp 0))
2323 ;; atanh(x) = -atanh(-x)
2324 (mul -
1 (fpatanh (bcons (fpminus fp-x
)))))
2325 ((fpgreaterp fp-x
(fpone))
2326 ;; x > 1, so use complex version.
2327 (multiple-value-bind (u v
)
2328 (complex-atanh x
(bcons (intofp 0)))
2329 (add u
(mul '$%i v
))))
2330 ((fpgreaterp fp-x
(cdr bfhalf
))
2331 ;; atanh(x) = 1/2*log1p(2*x/(1-x))
2333 (fptimes* (cdr bfhalf
)
2334 (fplog1p (fpquotient (fptimes* (intofp 2) fp-x
)
2335 (fpdifference (fpone) fp-x
))))))
2337 ;; atanh(x) = 1/2*log1p(2*x + 2*x*x/(1-x))
2338 (let ((2x (fptimes* (intofp 2) fp-x
)))
2340 (fptimes* (cdr bfhalf
)
2342 (fpquotient (fptimes* 2x fp-x
)
2343 (fpdifference (fpone) fp-x
)))))))))))
2345 ;; Stuff which follows is derived from atanh z = (log(1 + z) - log(1 - z))/2
2346 ;; which apparently originates with Kahan's "Much ado" paper.
2348 ;; The formulas for eta and nu below can be easily derived from
2349 ;; rectform(atanh(x+%i*y)) =
2351 ;; 1/4*log(((1+x)^2+y^2)/((1-x)^2+y^2)) + %i/2*(arg(1+x+%i*y)-arg(1-x+%i*(-y)))
2353 ;; Expand the argument of log out and divide it out and we get
2355 ;; log(((1+x)^2+y^2)/((1-x)^2+y^2)) = log(1+4*x/((1-x)^2+y^2))
2357 ;; When y = 0, Im atanh z = 1/2 (arg(1 + x) - arg(1 - x))
2358 ;; = if x < -1 then %pi/2 else if x > 1 then -%pi/2 else 0
2360 ;; Otherwise, arg(1 - x + %i*(-y)) = - arg(1 - x + %i*y),
2361 ;; and Im atanh z = 1/2 (arg(1 + x + %i*y) + arg(1 - x + %i*y)).
2362 ;; Since arg(x)+arg(y) = arg(x*y) (almost), we can simplify the
2363 ;; imaginary part to
2365 ;; arg((1+x+%i*y)*(1-x+%i*y)) = arg((1-x)*(1+x)-y^2+2*y*%i)
2366 ;; = atan2(2*y,((1-x)*(1+x)-y^2))
2368 ;; These are the eta and nu forms below.
2369 (defun complex-atanh (x y
)
2370 (let* ((fpx (cdr (bigfloatp x
)))
2371 (fpy (cdr (bigfloatp y
)))
2372 (beta (if (minusp (car fpx
))
2375 (x-lt-minus-1 (mevalp `((mlessp) ,x -
1)))
2376 (x-gt-plus-1 (mevalp `((mgreaterp) ,x
1)))
2377 (y-equals-0 (like y
'((bigfloat) 0 0)))
2378 (x (fptimes* beta fpx
))
2379 (y (fptimes* beta
(fpminus fpy
)))
2380 ;; Kahan has rho = 4/most-positive-float. What should we do
2381 ;; here about that? Our big floats don't really have a
2382 ;; most-positive float value.
2384 (t1 (fpplus (fpabs y
) rho
))
2385 (t1^
2 (fptimes* t1 t1
))
2386 (1-x (fpdifference (fpone) x
))
2387 ;; eta = log(1+4*x/((1-x)^2+y^2))/4
2389 (fplog1p (fpquotient (fptimes* (intofp 4) x
)
2390 (fpplus (fptimes* 1-x
1-x
)
2393 ;; If y = 0, then Im atanh z = %pi/2 or -%pi/2 or 0 depending
2394 ;; on whether x > 1, x < -1 or |x| <=1, respectively.
2396 ;; Otherwise nu = 1/2*atan2(2*y,(1-x)*(1+x)-y^2)
2398 ;; Extra fpminus here to counteract fpminus in return
2399 ;; value because we don't support signed zeroes.
2400 (fpminus (if x-lt-minus-1
2401 (cdr ($bfloat
'((mquotient) $%pi
2)))
2403 (cdr ($bfloat
'((mminus) ((mquotient) $%pi
2))))
2405 (fptimes* (cdr bfhalf
)
2406 (fpatan2 (fptimes* (intofp 2) y
)
2407 (fpdifference (fptimes* 1-x
(fpplus (fpone) x
))
2409 (values (bcons (fptimes* beta eta
))
2410 ;; Minus sign here because Kahan's algorithm assumed
2411 ;; signed zeroes, which we don't have in maxima.
2412 (bcons (fpminus (fptimes* beta nu
))))))
2414 (defun big-float-atanh (x &optional y
)
2416 (multiple-value-bind (u v
) (complex-atanh x y
)
2417 (add u
(mul '$%i v
)))
2420 ;; acos(x) for real x. X is a bigfloat, and a maxima number is returned.
2422 ;; acos(x) = %pi/2 - asin(x)
2423 ($bfloat
(add (div '$%pi
2) (mul -
1 (fpasin-core x
)))))
2425 (defun complex-acos (x y
)
2426 (let ((x (cdr (bigfloatp x
)))
2427 (y (cdr (bigfloatp y
))))
2428 (multiple-value-bind (re-sqrt-1-z im-sqrt-1-z
)
2429 (complex-sqrt (bcons (fpdifference (intofp 1) x
))
2430 (bcons (fpminus y
)))
2431 (multiple-value-bind (re-sqrt-1+z im-sqrt-1
+z
)
2432 (complex-sqrt (bcons (fpplus (intofp 1) x
))
2435 (fptimes* (intofp 2)
2436 (fpatan (fpquotient re-sqrt-1-z re-sqrt-1
+z
))))
2439 (fptimes* re-sqrt-1
+z im-sqrt-1-z
)
2440 (fptimes* im-sqrt-1
+z re-sqrt-1-z
)))))))))
2443 (defun big-float-acos (x &optional y
)
2445 (multiple-value-bind (u v
) (complex-acos x y
)
2446 (add u
(mul '$%i v
)))
2449 (defun complex-log (x y
)
2450 (let* ((x (cdr (bigfloatp x
)))
2451 (y (cdr (bigfloatp y
)))
2452 (t1 (let (($float2bf t
))
2453 ;; No warning message, please.
2456 (rho (fpplus (fptimes* x x
)
2460 (beta (fpmax abs-x abs-y
))
2461 (theta (fpmin abs-x abs-y
)))
2462 (values (if (or (fpgreaterp t1 beta
)
2464 (fpquotient (fplog1p (fpplus (fptimes* (fpdifference beta
(fpone))
2465 (fpplus beta
(fpone)))
2466 (fptimes* theta theta
)))
2468 (fpquotient (fplog rho
) (intofp 2)))
2471 (defun big-float-log (x &optional y
)
2473 (multiple-value-bind (u v
) (complex-log x y
)
2474 (add (bcons u
) (mul '$%i
(bcons v
))))
2476 ;; x is (mantissa exp), where mantissa = frac*2^fpprec,
2477 ;; with 1/2 < frac <= 1 and x is frac*2^exp. To
2478 ;; compute log(x), use log(x) = log(frac)+ exp*log(2).
2481 (fpprec (+ fpprec extra
))
2485 (cl-rat-to-maxima (/ (car x
)
2486 (ash 1 (- fpprec
8))))))
2487 (list (ash (car x
) extra
) 0)))
2488 (log-exp (fptimes* (intofp (second x
)) (fplog2)))
2489 (result (bcons (fpplus log-frac log-exp
))))
2490 (let ((fpprec (- fpprec extra
)))
2491 (bigfloatp result
))))))
2492 (let ((fp-x (cdr (bigfloatp x
))))
2494 ;; Special case for log(1). See:
2495 ;; https://sourceforge.net/p/maxima/bugs/2240/
2497 ((fplessp fp-x
(intofp 0))
2498 ;; ??? Do we want to return an exact %i*%pi or a float
2500 (add (big-float-log (bcons (fpminus fp-x
)))
2501 (mul '$%i
(bcons (fppi)))))
2503 (bcons (%log fp-x
))))))))
2505 (defun big-float-sqrt (x &optional y
)
2507 (multiple-value-bind (u v
) (complex-sqrt x y
)
2508 (add (bcons u
) (mul '$%i
(bcons v
))))
2509 (let ((fp-x (cdr (bigfloatp x
))))
2510 (if (fplessp fp-x
(intofp 0))
2511 (mul '$%i
(bcons (fproot (bcons (fpminus fp-x
)) 2)))
2512 (bcons (fproot x
2))))))
2515 (:load-toplevel
:execute
)
2516 (fpprec1 nil $fpprec
)) ; Set up user's precision