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, roughtly, 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, roughtly, 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 ;; atan(y/x) taking into account the quadrant. (Also equal to
930 (cond ((equal (car x
) 0)
931 ;; atan(y/0) = atan(inf), but what sign?
932 (cond ((equal (car y
) 0)
933 (merror (intl:gettext
"atan2: atan2(0, 0) is undefined.")))
935 ;; We're on the negative imaginary axis, so -pi/2.
936 (fpquotient (fppi) (intofp -
2)))
938 ;; The positive imaginary axis, so +pi/2
939 (fpquotient (fppi) (intofp 2)))))
941 ;; x > 0. atan(y/x) is the correct value.
942 (fpatan (fpquotient y x
)))
944 ;; x < 0, and y > 0. We're in quadrant II, so the angle we
945 ;; want is pi+atan(y/x).
946 (fpplus (fppi) (fpatan (fpquotient y x
))))
948 ;; x <= 0 and y <= 0. We're in quadrant III, so the angle we
949 ;; want is atan(y/x)-pi.
950 (fpdifference (fpatan (fpquotient y x
)) (fppi)))))
952 (defun tanbigfloat (a)
954 (fpend (let ((fpprec (+ 8. fpprec
)))
956 (setq a
(cdr ($bfloat a
)))
957 (fpquotient (fpsin a t
) (fpsin a nil
)))
958 (t (list '(%tan
) a
))))))
960 ;; Returns a list of a mantissa and an exponent. This function MUST
961 ;; recognize any symbol in *builtin-numeric-constants* and compute a
962 ;; bfloat value for it.
964 (cond ((not (atom l
))
981 (list (fpround l
) (+ *m fpprec
)))))
983 ;; It seems to me that this function gets called on an integer
984 ;; and returns the mantissa portion of the mantissa/exponent pair.
986 ;; "STICKY BIT" CALCULATION FIXED 10/14/75 --RJF
987 ;; BASE must not get temporarily bound to NIL by being placed
988 ;; in a PROG list as this will confuse stepping programs.
990 (defun fpround (l &aux
(*print-base
* 10.
) *print-radix
*)
994 ;;*M will be positive if the precision of the argument is greater than
995 ;;the current precision being used.
996 (setq *m
(- (integer-length l
) fpprec
))
1000 ;;FPSHIFT is essentially LSH.
1001 (setq adjust
(fpshift 1 (1- *m
)))
1002 (when (minusp l
) (setq adjust
(- adjust
)))
1004 (setq *m
(- (integer-length l
) fpprec
))
1005 (setq *cancelled
(abs *m
))
1006 (cond ((zerop (hipart l
(- *m
)))
1007 ;ONLY ZEROES SHIFTED OFF
1008 (return (fpshift (fpshift l
(- -
1 *m
))
1009 1))) ; ROUND TO MAKE EVEN
1010 (t (return (fpshift l
(- *m
))))))
1012 (setq *m
(- (flatsize (abs l
)) fpprec
))
1013 (setq adjust
(fpshift 1 (1- *m
)))
1014 (when (minusp l
) (setq adjust
(- adjust
)))
1015 (setq adjust
(* 5 adjust
))
1016 (setq *m
(- (flatsize (abs (setq l
(+ l adjust
)))) fpprec
))
1017 (return (fpshift l
(- *m
)))))))
1019 ;; Compute (* L (expt d n)) where D is 2 or 10 depending on
1020 ;; *decfp. Throw away an fractional part by truncating to zero.
1021 (defun fpshift (l n
)
1022 (cond ((null *decfp
)
1023 (cond ((and (minusp n
) (minusp l
))
1024 ;; Left shift of negative number requires some
1025 ;; care. (That is, (truncate l (expt 2 n)), but use
1033 (quotient l
(expt 10.
(- n
))))
1036 ;; Bignum LSH -- N is assumed (and declared above) to be a fixnum.
1037 ;; This isn't really LSH, since the sign bit isn't propagated when
1038 ;; shifting to the right, i.e. (BIGLSH -100 -3) = -40, whereas
1039 ;; (LSH -100 -3) = 777777777770 (on a 36 bit machine).
1040 ;; This actually computes (* X (EXPT 2 N)). As of 12/21/80, this function
1041 ;; was only called by FPSHIFT. I would like to hear an argument as why this
1042 ;; is more efficient than simply writing (* X (EXPT 2 N)). Is the
1043 ;; intermediate result created by (EXPT 2 N) the problem? I assume that
1044 ;; EXPT tries to LSH when possible.
1047 (cond ((and (not (bignump x
))
1048 (< n
#.
(- +machine-fixnum-precision
+)))
1050 ;; Either we are shifting a fixnum to the right, or shifting
1051 ;; a fixnum to the left, but not far enough left for it to become
1053 ((and (not (bignump x
))
1055 (< (+ (integer-length x
) n
) #.
+machine-fixnum-precision
+)))
1056 ;; The form which follows is nearly identical to (ASH X N), however
1057 ;; (ASH -100 -20) = -1, whereas (BIGLSH -100 -20) = 0.
1060 (- (biglsh (- x
) n
)))) ;(- x) may be a bignum even is x is a fixnum.
1061 ;; If we get here, then either X is a bignum or our answer is
1062 ;; going to be a bignum.
1064 (cond ((> (abs n
) (integer-length x
)) 0)
1066 (hipart x
(+ (integer-length x
) n
)))
1067 (t (- (hipart x
(+ (integer-length x
) n
))))))
1069 ;; Isn't this the kind of optimization that compilers are
1070 ;; supposed to make?
1071 ((< n
#.
(1- +machine-fixnum-precision
+)) (* x
(ash 1 n
)))
1072 (t (* x
(expt 2 n
)))))
1077 ;; For negative x, use exp(-x) = 1/exp(x)
1079 ;; For x > 0, exp(x) = exp(r+y) = exp(r) * exp(y), where x = r + y and
1083 (unless (signp ge
(car x
))
1084 (return (fpquotient (fpone) (fpexp (fpabs x
)))))
1085 (setq r
(fpintpart x
:skip-exponent-check-p t
))
1086 (return (cond ((< r
2)
1089 (setq s
(fpexp1 (fpdifference x
(intofp r
))))
1092 (let ((fpprec (+ fpprec
(integer-length r
) -
1))
1094 (bcons (fpexpt (fpe) r
))))))))))) ; patch for full precision %E
1096 ;; exp(x) for small x, using Taylor series.
1098 (prog (term ans oans
)
1099 (setq ans
(setq term
(fpone)))
1102 (setq term
(fpquotient (fptimes* x term
) (intofp n
)))
1104 (setq ans
(fpplus ans term
)))
1107 ;; Does one higher precision to round correctly.
1108 ;; A and B are each a list of a mantissa and an exponent.
1109 (defun fpquotient (a b
)
1110 (cond ((equal (car b
) 0)
1111 (merror (intl:gettext
"pquotient: attempted quotient by zero.")))
1112 ((equal (car a
) 0) '(0 0))
1113 (t (list (fpround (quotient (fpshift (car a
) (+ 3 fpprec
)) (car b
)))
1114 (+ -
3 (- (cadr a
) (cadr b
)) *m
)))))
1116 (defun fpgreaterp (a b
)
1117 (fpposp (fpdifference a b
)))
1119 (defun fplessp (a b
)
1120 (fpposp (fpdifference b a
)))
1125 (defun fpmin (arg1 &rest args
)
1127 (mapc #'(lambda (u) (if (fplessp u min
) (setq min u
))) args
)
1130 (defun fpmax (arg1 &rest args
)
1132 (mapc #'(lambda (u) (if (fpgreaterp u max
) (setq max u
))) args
)
1135 ;; The following functions compute bigfloat values for %e, %pi,
1136 ;; %gamma, and log(2). For each precision, the computed value is
1137 ;; cached in a hash table so it doesn't need to be computed again.
1138 ;; There are functions to return the hash table or clear the hash
1139 ;; table, for debugging.
1141 ;; Note that each of these return a bigfloat number, but without the
1145 ;; https://sourceforge.net/p/maxima/bugs/1842/
1146 ;; for an explanation.
1148 ((memoize (name compute-form
)
1149 ;; Macro creates a closure over a hash table containing the
1150 ;; bigfloat values of a constant. The key of the hash table is
1151 ;; the number of bits of precision of the bigfloat. This keeps
1152 ;; Maxima from constantly computing the numeric value of a
1153 ;; constant. Once computed for a certain precision, we can
1154 ;; just look up precomputed value.
1156 ;; A function with the name NAME is created that looks up the
1157 ;; value in hash table. If it exists, return it. If not
1158 ;; update the hash table with a new value computed via
1159 ;; COMPUTE-FORM. This value is returned.
1161 ;; For debugging, we define a function to get the hash table
1162 ;; and a function to clear the hash table of all entries.
1163 (let ((table-getter-name
1164 (intern (concatenate 'string
(string name
) "-TABLE")))
1166 (intern (concatenate 'string
1167 "CLEAR_" (string name
) "_TABLE")))
1168 (table-name (gensym (concatenate 'string
"TABLE-" (string name
)))))
1169 `(let ((,table-name
(make-hash-table)))
1171 (let ((value (gethash fpprec
,table-name
)))
1174 (setf (gethash fpprec
,table-name
) ,compute-form
))))
1175 (defun ,table-getter-name
()
1177 (defun ,table-clearer-name
()
1178 (clrhash ,table-name
))))))
1179 (memoize fpe
(cdr (fpe1)))
1180 (memoize fppi
(cdr (fppi1)))
1181 (memoize fpgamma
(cdr (fpgamma1)))
1182 (memoize fplog2
(comp-log2))
1183 (memoize fpcatalan
(cdr (fpcatalan1)))
1184 (memoize fpphi
(cdr (fpphi1))))
1186 ;; This doesn't need a hash table because there's never a problem with
1187 ;; using a high precision value and rounding to a lower precision
1188 ;; value because 1 is always an exact bfloat.
1190 (cond (*decfp
(intofp 1))
1191 ((= fpprec
(bigfloat-prec bigfloatone
)) (cdr bigfloatone
))
1194 ;;----------------------------------------------------------------------------;;
1196 ;; The values of %e, %pi, %gamma and log(2) are computed by the technique of
1197 ;; binary splitting. See http://www.ginac.de/CLN/binsplit.pdf for details.
1199 ;; Volker van Nek, Sept. 2014
1205 (let ((e (compe (+ fpprec
12)))) ;; compute additional bits
1206 (bcons (list (fpround (car e
)) (cadr e
))) )) ;; round to fpprec
1208 ;; Taylor: %e = sum(s[i] ,i,0,inf) where s[i] = 1/i!
1211 (let ((fpprec prec
))
1212 (multiple-value-bind (tt qq
) (split-taylor-e 0 (taylor-e-size prec
))
1213 (fpquotient (intofp tt
) (intofp qq
)) )))
1215 ;; binary splitting:
1218 ;; s[i] = ----------------------
1219 ;; q[0]*q[1]*q[2]*..*q[i]
1224 (defun split-taylor-e (i j
)
1227 (setq qq
(if (= i
0) 1 i
)
1229 (let ((m (ash (+ i j
) -
1)))
1230 (multiple-value-bind (tl ql
) (split-taylor-e i m
)
1231 (multiple-value-bind (tr qr
) (split-taylor-e m j
)
1233 tt
(+ (* qr tl
) tr
) )))))
1236 ;; stop when i! > 2^fpprec
1238 ;; log(i!) = sum(log(k), k,1,i) > fpprec * log(2)
1240 (defun taylor-e-size (prec)
1242 (lim (* prec
(log 2))) )
1245 (incf acc
(log i
)) )))
1247 ;;----------------------------------------------------------------------------;;
1252 (let ((pi1 (comppi (+ fpprec
10))))
1253 (bcons (list (fpround (car pi1
)) (cadr pi1
))) ))
1255 ;; Chudnovsky & Chudnovsky:
1257 ;; C^(3/2)/(12*%pi) = sum(s[i], i,0,inf),
1259 ;; where s[i] = (-1)^i*(6*i)!*(A*i+B) / (i!^3*(3*i)!*C^(3*i))
1261 ;; and A = 545140134, B = 13591409, C = 640320
1263 (defun comppi (prec)
1265 nr n d oldn tt qq n
*qq
)
1267 ;; compute n/d = sqrt(10005) :
1269 ;; n[0] n[i+1] = n[i]^2+a*d[i]^2 n[inf]
1270 ;; quadratic Heron: x[0] = ----, , sqrt(a) = ------
1271 ;; d[0] d[i+1] = 2*n[i]*d[i] d[inf]
1273 (multiple-value-setq (nr n d
) (sqrt-10005-constants fpprec
))
1276 n
(+ (* n n
) (* 10005 d d
))
1279 ;; divide C^(3/2)/12 = 3335*2^7*sqrt(10005)
1280 ;; by Chudnovsky-sum = tt/qq :
1282 (setq nr
(ceiling (* fpprec
0.021226729578153))) ;; nr of summands
1283 ;; fpprec*log(2)/log(C^3/(24*6*2*6))
1284 (multiple-value-setq (tt qq
) (split-chudnovsky 0 (1+ nr
)))
1286 n
*qq
(intofp (* n qq
)) )
1287 (fpquotient (list (car n
*qq
) (+ (cadr n
*qq
) 7))
1288 (intofp (* d tt
)) )))
1290 ;; The returned n and d serve as start values for the iteration.
1291 ;; n/d = sqrt(10005) with a precision of p = ceiling(prec/2^nr) bits
1292 ;; where nr is the number of needed iterations.
1294 (defun sqrt-10005-constants (prec)
1295 (let (ilen p nr n d
)
1298 (setq ilen
(integer-length prec
)
1300 p
(ceiling (* prec
(expt 2.0 (- nr
)))) ))
1302 ((<= p
76) (setq n
256192036001 d
2561280120))
1303 ((<= p
89) (setq n
51244811200700 d
512320048001))
1304 ((<= p
102) (setq n
2050048640064001 d
20495363200160))
1305 ((<= p
115) (setq n
410060972824000900 d
4099584960080001))
1306 (t (setq n
16404488961600100001 d
164003893766400200)) )
1309 ;; binary splitting:
1311 ;; a[i] * p[0]*p[1]*p[2]*..*p[i]
1312 ;; s[i] = -----------------------------
1313 ;; q[0]*q[1]*q[2]*..*q[i]
1318 ;; p[i] = - (6*i-5)*(2*i-1)*(6*i-1)
1319 ;; q[i] = C^3/24*i^3
1321 (defun split-chudnovsky (i j
)
1322 (let (aa pp
/qq pp qq tt
)
1325 (setq aa
13591409 pp
1 qq
1 tt aa
)
1326 (setq aa
(+ (* i
545140134) 13591409)
1327 pp
/qq
(/ (* (- 5 (* 6 i
)) (- (* 2 i
) 1) (- (* 6 i
) 1))
1328 10939058860032000 ) ; C^3/24
1329 pp
(numerator pp
/qq
)
1330 qq
(* (denominator pp
/qq
) (expt i
3))
1332 (let ((m (ash (+ i j
) -
1)))
1333 (multiple-value-bind (tl ql pl
) (split-chudnovsky i m
)
1334 (multiple-value-bind (tr qr pr
) (split-chudnovsky m j
)
1337 tt
(+ (* qr tl
) (* pl tr
)) )))))
1338 (values tt qq pp
) ))
1340 ;;----------------------------------------------------------------------------;;
1342 ;; Euler-Mascheroni constant GAMMA
1345 (let ((res (comp-bf%gamma
(+ fpprec
14))))
1346 (bcons (list (fpround (car res
)) (cadr res
))) ))
1348 ;; Brent-McMillan algorithm
1351 ;; alpha = 4.970625759544
1353 ;; n > 0 and N-1 >= alpha*n
1355 ;; H(k) = sum(1/i, i,1,k)
1357 ;; S = sum(H(k)*(n^k/k!)^2, k,0,N-1)
1359 ;; I = sum((n^k/k!)^2, k,0,N-1)
1361 ;; T = 1/(4*n)*sum((2*k)!^3/(k!^4*(16*n)^(2*k)), k,0,2*n-1)
1364 ;; %gamma = S/I - T/I^2 - log(n)
1367 ;; |%gamma - gamma| < 24 * e^(-8*n)
1369 ;; (Corollary 2, Remark 2, Brent/Johansson http://arxiv.org/pdf/1312.0039v1.pdf)
1371 (defun comp-bf%gamma
(prec)
1372 (let* ((fpprec prec
)
1373 (n (ceiling (* 1/8 (+ (* prec
(log 2.0)) (log 24.0)))))
1375 (alpha 4.970625759544)
1376 (lim (ceiling (* alpha n
)))
1378 sumi sumi2
;; I and I^2
1379 sumt
/sumi2
) ;; T/I^2
1380 (multiple-value-bind (vv tt qq dd
) (split-gamma-1 1 (1+ lim
) n2
)
1382 ;; sums = vv/(qq*dd)
1384 ;; sums/sumi = vv/(qq*dd)*qq/tt = vv/(dd*tt)
1386 (setq sums
/sumi
(fpquotient (intofp vv
) (intofp (* dd tt
)))
1387 sumi
(fpquotient (intofp tt
) (intofp qq
))
1388 sumi2
(fptimes* sumi sumi
) )
1390 (multiple-value-bind (ttt qqq
) (split-gamma-2 0 (* 2 n
) (* 32 n2
))
1392 ;; sumt = 1/(4*n)*ttt/qqq
1393 ;; sumt/sumi2 = ttt/(4*n*qqq*sumi2)
1395 (setq sumt
/sumi2
(fpquotient (intofp ttt
)
1396 (fptimes* (intofp (* 4 n qqq
)) sumi2
) ))
1398 (fpdifference sums
/sumi
(fpplus sumt
/sumi2
(log-n n
)) )))))
1400 ;; split S and I simultaneously:
1402 ;; summands I[0] = 1, I[i]/I[i-1] = n^2/i^2
1404 ;; S[0] = 0, S[i]/S[i-1] = n^2/i^2*H(i)/H(i-1)
1406 ;; p[0]*p[1]*p[2]*..*p[i]
1407 ;; I[i] = ----------------------
1408 ;; q[0]*q[1]*q[2]*..*q[i]
1414 ;; c[0] c[1] c[2] c[i]
1415 ;; S[i] = H[i] * I[i], where H[i] = ---- + ---- + ---- + .. + ----
1416 ;; d[0] d[1] d[2] d[i]
1422 (defun split-gamma-1 (i j n2
)
1423 (let (pp cc dd qq tt vv
)
1426 (if (= i
1) ;; S[0] is 0 -> start with i=1 and add I[0]=1 to tt :
1427 (setq pp n2 cc
1 dd
1 qq
1 tt
(1+ n2
) vv n2
)
1428 (setq pp n2 cc
1 dd i qq
(* i i
) tt pp vv tt
) ))
1430 (let* ((m (ash (+ i j
) -
1)) tmp
)
1431 (multiple-value-bind (vl tl ql dl cl pl
) (split-gamma-1 i m n2
)
1432 (multiple-value-bind (vr tr qr dr cr pr
) (split-gamma-1 m j n2
)
1434 cc
(+ (* cl dr
) (* dl cr
))
1438 tt
(+ (* tl qr
) tmp
)
1439 vv
(+ (* dr
(+ (* vl qr
) (* cl tmp
))) (* dl pl vr
)) ))))))
1440 (values vv tt qq dd cc pp
) ))
1444 ;; summands T[0] = 1, T[i]/T[i-1] = (2*i-1)^3/(32*i*n^2)
1446 ;; p[0]*p[1]*p[2]*..*p[i]
1447 ;; T[i] = ----------------------
1448 ;; q[0]*q[1]*q[2]*..*q[i]
1450 ;; where p[0] = q[0] = 1
1454 (defun split-gamma-2 (i j n2
*32)
1459 (setq pp
1 qq
1 tt
1)
1460 (setq pp
(expt (1- (* 2 i
)) 3) qq
(* i n2
*32) tt pp
) ))
1462 (let* ((m (ash (+ i j
) -
1)))
1463 (multiple-value-bind (tl ql pl
) (split-gamma-2 i m n2
*32)
1464 (multiple-value-bind (tr qr pr
) (split-gamma-2 m j n2
*32)
1467 tt
(+ (* tl qr
) (* pl tr
)) ))))))
1468 (values tt qq pp
) ))
1470 ;;----------------------------------------------------------------------------;;
1472 ;; log(2) = 18*L(26) - 2*L(4801) + 8*L(8749)
1474 ;; where L(k) = atanh(1/k)
1476 ;; see http://numbers.computation.free.fr/Constants/constants.html
1478 ;;;(defun $log2 () (bcons (comp-log2))) ;; checked against reference table
1482 (let ((fpprec (+ fpprec
12)))
1484 (fpdifference (n*atanh-1
/k
18 26) (n*atanh-1
/k
2 4801))
1485 (n*atanh-1
/k
8 8749) ))))
1486 (list (fpround (car res
)) (cadr res
)) ))
1488 ;; Taylor: atanh(1/k) = sum(s[i], i,0,inf)
1490 ;; where s[i] = 1/((2*i+1)*k^(2*i+1))
1492 (defun n*atanh-1
/k
(n k
) ;; integer n,k
1494 (nr (ceiling (* fpprec
(/ (log 2) (log k2
))))) )
1495 (multiple-value-bind (tt qq bb
) (split-atanh-1/k
0 (1+ nr
) k k2
)
1496 (fpquotient (intofp (* n tt
)) (intofp (* bb qq
))) )))
1498 ;; binary splitting:
1500 ;; s[i] = -----------------------------
1501 ;; b[i] * q[0]*q[1]*q[2]*..*q[i]
1508 (defun split-atanh-1/k
(i j k k2
)
1512 (setq bb
1 qq k tt
1)
1513 (setq bb
(1+ (* 2 i
)) qq k2 tt
1) )
1514 (let ((m (ash (+ i j
) -
1)))
1515 (multiple-value-bind (tl ql bl
) (split-atanh-1/k i m k k2
)
1516 (multiple-value-bind (tr qr br
) (split-atanh-1/k m j k k2
)
1519 tt
(+ (* br qr tl
) (* bl tr
)) )))))
1520 (values tt qq bb
) ))
1522 ;;----------------------------------------------------------------------------;;
1524 ;; log(n) = log(n/2^k) + k*log(2)
1526 ;;;(defun $log10 () (bcons (log-n 10))) ;; checked against reference table
1528 (defun log-n (n) ;; integer n > 0
1530 ((= 1 n
) (list 0 0))
1531 ((= 2 n
) (comp-log2))
1534 (let ((fpprec (+ fpprec
10))
1535 (k (integer-length n
)) )
1536 ;; choose k so that |n/2^k - 1| is as small as possible:
1537 (when (< n
(* (coerce 2/3 'flonum
) (ash 1 k
))) (decf k
))
1538 ;; now |n/2^k - 1| <= 1/3
1539 (fpplus (log-u/2^k n k fpprec
)
1540 (fptimes* (intofp k
) (comp-log2)) ))))
1541 (list (fpround (car res
)) (cadr res
)) ))))
1543 ;; log(1+u/v) = 2 * sum(s[i], i,0,inf)
1545 ;; where s[i] = (u/(2*v+u))^(2*i+1)/(2*i+1)
1547 (defun log-u/2^k
(u k prec
) ;; integer u k; x = u/2^k; |x - 1| < 1
1548 (setq u
(- u
(ash 1 k
))) ;; x <-- x - 1
1550 ((= 0 u
) (list 0 0))
1552 (while (evenp u
) (setq u
(ash u -
1)) (decf k
))
1556 (nr (ceiling (* prec
(/ (log 2) 2 (log (abs (/ w u
)))))))
1558 (multiple-value-bind (tt qq bb
) (split-log-1+u
/v
0 (1+ nr
) u u2 w w2
)
1559 (setq lg
/2 (fpquotient (intofp tt
) (intofp (* bb qq
)))) ;; sum
1560 (list (car lg
/2) (1+ (cadr lg
/2))) ))))) ;; 2*sum
1562 ;; binary splitting:
1564 ;; p[0]*p[1]*p[2]*..*p[i]
1565 ;; s[i] = -----------------------------
1566 ;; b[i] * q[0]*q[1]*q[2]*..*q[i]
1575 (defun split-log-1+u
/v
(i j u u2 w w2
)
1579 (setq pp u bb
1 qq w tt u
)
1580 (setq pp u2 bb
(1+ (* 2 i
)) qq w2 tt pp
) )
1581 (let ((m (ash (+ i j
) -
1)))
1582 (multiple-value-bind (tl ql bl pl
) (split-log-1+u
/v i m u u2 w w2
)
1583 (multiple-value-bind (tr qr br pr
) (split-log-1+u
/v m j u u2 w w2
)
1587 tt
(+ (* br qr tl
) (* bl pl tr
)) )))))
1588 (values tt qq bb pp
) ))
1590 ;;----------------------------------------------------------------------------;;
1591 (defun fpcatalan1 ()
1592 ;; Use 5 extra bits when computing %catalan. Not exactly sure what
1593 ;; is right value, but 5 seems good enough.
1594 (let ((catalan (cdr (bigfloat::comp-catalan
(+ fpprec
5)))))
1595 ;; Round value that has extra bits to the current number of bits
1597 (bcons (list (fpround (car catalan
))
1603 (let* ((phi (let ((fpprec (+ fpprec
2)))
1604 ;; Use couple of extra bits to compute %phi =
1606 (cdr ($bfloat
(div (add 1 (power 5 1//2))
1608 ;; Round value that has extra bits to the current number of bits
1610 (bcons (list (fpround (car phi
))
1614 ;;----------------------------------------------------------------------------;;
1617 (defun fpdifference (a b
)
1618 (fpplus a
(fpminus b
)))
1621 (if (equal (car x
) 0)
1623 (list (- (car x
)) (cadr x
))))
1626 (prog (*m exp man sticky
)
1628 (cond ((equal (car a
) 0) (return b
))
1629 ((equal (car b
) 0) (return a
)))
1630 (setq exp
(- (cadr a
) (cadr b
)))
1631 (setq man
(cond ((equal exp
0)
1633 (fpshift (+ (car a
) (car b
)) 2))
1635 (setq sticky
(hipart (car b
) (- 1 exp
)))
1636 (setq sticky
(cond ((signp e sticky
) 0)
1637 ((signp l
(car b
)) -
1)
1639 ; COMPUTE STICKY BIT
1640 (+ (fpshift (car a
) 2)
1641 ; MAKE ROOM FOR GUARD DIGIT & STICKY BIT
1642 (fpshift (car b
) (- 2 exp
))))
1643 (t (setq sticky
(hipart (car a
) (1+ exp
)))
1644 (setq sticky
(cond ((signp e sticky
) 0)
1645 ((signp l
(car a
)) -
1)
1647 (+ (fpshift (car b
) 2)
1648 (fpshift (car a
) (+ 2 exp
))))))
1649 (setq man
(+ man sticky
))
1650 (return (cond ((equal man
0) '(0 0))
1651 (t (setq man
(fpround man
))
1652 (setq exp
(+ -
2 *m
(max (cadr a
) (cadr b
))))
1655 (defun fptimes* (a b
)
1656 (if (or (zerop (car a
)) (zerop (car b
)))
1658 (list (fpround (* (car a
) (car b
)))
1659 (+ *m
(cadr a
) (cadr b
) (- fpprec
)))))
1661 ;; Don't use the symbol BASE since it is SPECIAL.
1663 (defun fpintexpt (int nn fixprec
) ;INT is integer
1664 (setq fixprec
(truncate fixprec
(1- (integer-length int
)))) ;NN is pos
1665 (let ((bas (intofp (expt int
(min nn fixprec
)))))
1667 (fptimes* (intofp (expt int
(rem nn fixprec
)))
1668 (fpexpt bas
(quotient nn fixprec
)))
1671 ;; NN is positive or negative integer
1673 (defun fpexpt (p nn
)
1674 (cond ((zerop nn
) (fpone))
1676 ((< nn
0) (fpquotient (fpone) (fpexpt p
(- nn
))))
1681 (do ((ii (quotient nn
2) (quotient ii
2)))
1683 (setq p
(fptimes* p p
))
1685 (setq u
(fptimes* u p
))))
1688 (defun exptbigfloat (p n
)
1689 (cond ((equal n
1) p
)
1690 ((equal n
0) ($bfloat
1))
1691 ((not ($bfloatp p
)) (list '(mexpt) p n
))
1692 ((equal (cadr p
) 0) ($bfloat
0))
1693 ((and (< (cadr p
) 0) (ratnump n
))
1694 (mul2 (let ($numer $float $keepfloat $ratprint
)
1696 (exptbigfloat (bcons (fpminus (cdr p
))) n
)))
1697 ((and (< (cadr p
) 0) (not (integerp n
)))
1698 (cond ((or (equal n
0.5) (equal n bfhalf
))
1699 (exptbigfloat p
'((rat simp
) 1 2)))
1700 ((or (equal n -
0.5) (equal n bfmhalf
))
1701 (exptbigfloat p
'((rat simp
) -
1 2)))
1702 (($bfloatp
(setq n
($bfloat n
)))
1703 (cond ((equal n
($bfloat
(fpentier n
)))
1704 (exptbigfloat p
(fpentier n
)))
1705 (t ;; for P<0: P^N = (-P)^N*cos(pi*N) + i*(-P)^N*sin(pi*N)
1706 (setq p
(exptbigfloat (bcons (fpminus (cdr p
))) n
)
1707 n
($bfloat
`((mtimes) $%pi
,n
)))
1708 (add2 ($bfloat
`((mtimes) ,p
,(*fpsin n nil
)))
1709 `((mtimes simp
) ,($bfloat
`((mtimes) ,p
,(*fpsin n t
)))
1711 (t (list '(mexpt) p n
))))
1712 ((and (ratnump n
) (< (caddr n
) 10.
))
1713 (bcons (fpexpt (fproot p
(caddr n
)) (cadr n
))))
1715 (setq n
($bfloat n
))
1717 ((not ($bfloatp n
)) (list '(mexpt) p n
))
1719 (let ((extrabits (max 1 (+ (caddr n
) (integer-length (caddr p
))))))
1721 (let ((fpprec (+ extrabits fpprec
)))
1722 (fpexp (fptimes* (cdr (bigfloatp n
)) (fplog (cdr (bigfloatp p
)))))))
1723 (setq p
(list (fpround (car p
)) (+ (- extrabits
) *m
(cadr p
))))
1725 ;; The number of extra bits required
1726 ((< n
0) (invertbigfloat (exptbigfloat p
(- n
))))
1727 (t (bcons (fpexpt (cdr p
) n
)))))
1729 (defun fproot (a n
) ; computes a^(1/n) see Fitch, SIGSAM Bull Nov 74
1731 ;; Special case for a = 0b0. General algorithm loops endlessly in that case.
1733 ;; Unlike many or maybe all of the other functions named FP-something,
1734 ;; FPROOT assumes it is called with an argument like
1735 ;; '((BIGFLOAT ...) FOO BAR) instead of '(FOO BAR).
1736 ;; However FPROOT does return something like '(FOO BAR).
1738 (if (eql (cadr a
) 0)
1741 (let* ((ofprec fpprec
)
1742 (fpprec (+ fpprec
2)) ;assumes a>0 n>=2
1743 (bk (fpexpt (intofp 2) (1+ (quotient (cadr (setq a
(cdr (bigfloatp a
)))) n
)))))
1744 (do ((x bk
(fpdifference x
1745 (setq bk
(fpquotient (fpdifference
1746 x
(fpquotient a
(fpexpt x n1
))) n
))))
1749 ((or (equal bk
'(0 0))
1750 (> (- (cadr x
) (cadr bk
)) ofprec
))
1752 (list (fpround (car a
)) (+ -
2 *m
(cadr a
))))))
1754 (defun timesbigfloat (h)
1755 (prog (fans r nfans
)
1756 (setq fans
(bcons (fpone)) nfans
1)
1759 (if (setq r
(bigfloatp (car l
)))
1760 (setq fans
(bcons (fptimes* (cdr r
) (cdr fans
))))
1761 (setq nfans
(list '(mtimes) (car l
) nfans
))))
1762 (return (if (equal nfans
1)
1764 (simplify (list '(mtimes) fans nfans
))))))
1766 (defun invertbigfloat (a)
1767 ;; If A is a bigfloat, be sure to round it to the current precision.
1768 ;; (See Bug 2543079 for one of the symptoms.)
1769 (let ((b (bigfloatp a
)))
1771 (bcons (fpquotient (fpone) (cdr b
)))
1772 (simplify (list '(mexpt) a -
1)))))
1775 (fpend (let ((fpprec (+ 8. fpprec
)))
1777 (fpexp (cdr (bigfloatp a
)))
1778 (list '(mexpt) '$%e a
)))))
1780 (defun *fpsin
(a fl
)
1781 (fpend (let ((fpprec (+ 8. fpprec
)))
1782 (cond (($bfloatp a
) (fpsin (cdr ($bfloat a
)) fl
))
1783 (fl (list '(%sin
) a
))
1784 (t (list '(%cos
) a
))))))
1787 (cond ((equal (car a
) 0) (bcons a
))
1789 (setq a
(list (fpround (car a
)) (+ -
8.
*m
(cadr a
))))
1793 (defun fparcsimp (e) ; needed for e.g. ASIN(.123567812345678B0) with
1794 ;; FPPREC 16, to get rid of the miniscule imaginary
1795 ;; part of the a+bi answer.
1796 (if (and (mplusp e
) (null (cdddr e
))
1797 (mtimesp (caddr e
)) (null (cdddr (caddr e
)))
1798 ($bfloatp
(cadr (caddr e
)))
1799 (eq (caddr (caddr e
)) '$%i
)
1800 (< (caddr (cadr (caddr e
))) (+ (- fpprec
) 2)))
1804 (defun sinbigfloat (x)
1807 (defun cosbigfloat (x)
1808 (*fpsin
(car x
) nil
))
1810 ;; THIS VERSION OF FPSIN COMPUTES SIN OR COS TO PRECISION FPPREC,
1811 ;; BUT CHECKS FOR THE POSSIBILITY OF CATASTROPHIC CANCELLATION DURING
1812 ;; ARGUMENT REDUCTION (E.G. SIN(N*%PI+EPSILON))
1813 ;; *FPSINCHECK* WILL CAUSE PRINTOUT OF ADDITIONAL INFO WHEN
1814 ;; EXTRA PRECISION IS NEEDED FOR SIN/COS CALCULATION. KNOWN
1815 ;; BAD FEATURES: IT IS NOT NECESSARY TO USE EXTRA PRECISION FOR, E.G.
1816 ;; SIN(PI/2), WHICH IS NOT NEAR ZERO, BUT EXTRA
1817 ;; PRECISION IS USED SINCE IT IS NEEDED FOR COS(PI/2).
1818 ;; PRECISION SEEMS TO BE 100% SATSIFACTORY FOR LARGE ARGUMENTS, E.G.
1819 ;; SIN(31415926.0B0), BUT LESS SO FOR SIN(3.1415926B0). EXPLANATION
1820 ;; NOT KNOWN. (9/12/75 RJF)
1822 (defvar *fpsincheck
* nil
)
1824 ;; FL is a T for sin and NIL for cos.
1826 (prog (piby2 r sign res k
*cancelled
)
1827 (setq sign
(cond (fl (signp g
(car x
)))
1830 (when (equal (car x
) 0)
1831 (return (if fl
(intofp 0) (intofp 1))))
1835 (let ((fpprec (max fpprec
(+ fpprec
(cadr x
))))
1840 loop
(setq x
(cdr (bigfloatp xt
)))
1841 (setq piby2
(fpquotient (fppi) (intofp 2)))
1842 (setq r
(fpintpart (fpquotient x piby2
) :skip-exponent-check-p t
))
1843 (setq x
(fpplus x
(fptimes* (intofp (- r
)) piby2
)))
1845 (fpplus x
(fpminus piby2
))
1846 (setq *cancelled
(max k
*cancelled
))
1848 (print `(*canc
= ,*cancelled fpprec
= ,fpprec oldprec
= ,oldprec
)))
1849 (cond ((not (> oldprec
(- fpprec
*cancelled
)))
1852 (cond (fl (cond ((= r
0) (fpsin1 x
))
1853 ((= r
1) (fpcos1 x
))
1854 ((= r
2) (fpminus (fpsin1 x
)))
1855 ((= r
3) (fpminus (fpcos1 x
)))))
1856 (t (cond ((= r
0) (fpcos1 x
))
1857 ((= r
1) (fpminus (fpsin1 x
)))
1858 ((= r
2) (fpminus (fpcos1 x
)))
1859 ((= r
3) (fpsin1 x
))))))
1860 (return (bcons (if sign res
(fpminus res
)))))
1862 (incf fpprec
*cancelled
)
1868 ;; Compute SIN or COS in (0,PI/2). FL is T for SIN, NIL for COS.
1870 ;; Use Taylor series
1871 (defun fpsincos1 (x fl
)
1872 (prog (ans term oans x2
)
1873 (setq ans
(if fl x
(intofp 1))
1874 x2
(fpminus(fptimes* x x
)))
1876 (do ((n (if fl
3 2) (+ n
2)))
1878 (setq term
(fptimes* term
(fpquotient x2
(intofp (* n
(1- n
))))))
1880 ans
(fpplus ans term
)))
1887 (if (signp ge
(car x
))
1889 (cons (- (car x
)) (cdr x
))))
1892 (let ((fpprec (bigfloat-prec f
)))
1893 (fpintpart (cdr f
))))
1895 ;; Calculate the integer part of a floating point number that is represented as
1898 ;; (MANTISSA EXPONENT)
1900 ;; The special variable fpprec should be bound to the precision (in bits) of the
1901 ;; number. This encodes how many bits are known of the result and also a right
1902 ;; shift. The pair denotes the number MANTISSA * 2^(EXPONENT - FPPREC), of which
1903 ;; FPPREC bits are known.
1905 ;; If EXPONENT is large and positive then we might not have enough
1906 ;; information to calculate the integer part. Specifically, we only
1907 ;; have enough information if EXPONENT < FPPREC. If that isn't the
1908 ;; case, we signal a Maxima error. However, if SKIP-EXPONENT-CHECK-P
1909 ;; is non-NIL, this check is skipped, and we compute the integer part
1912 ;; For the bigfloat code here, skip-exponent-check-p should be true.
1913 ;; For other uses (see commit 576c7508 and bug #2784), this should be
1914 ;; nil, which is the default.
1915 (defun fpintpart (f &key skip-exponent-check-p
)
1916 (destructuring-bind (mantissa exponent
)
1918 (let ((m (- fpprec exponent
)))
1920 (quotient mantissa
(expt 2 (- fpprec exponent
)))
1921 (if (and (not skip-exponent-check-p
) (< exponent fpprec
))
1922 (merror "~M doesn't have enough precision to compute its integer part"
1923 `((bigfloat ,fpprec
) ,mantissa
,exponent
))
1924 (* mantissa
(expt 2 (- m
))))))))
1926 (defun logbigfloat (a)
1927 (cond (($bfloatp
(car a
))
1928 (big-float-log ($bfloat
(car a
))))
1930 (list '(%log
) (car a
)))))
1933 ;;; Computes the log of a bigfloat number.
1937 ;;; log(1+x) = sum((x/(x+2))^(2*n+1)/(2*n+1),n,0,inf);
1943 ;;; = 2 > --------------
1949 ;;; which converges for x > 0.
1951 ;;; Note that FPLOG is given 1+X, not X.
1953 ;;; However, to aid convergence of the series, we scale 1+x until 1/e
1957 (prog (over two ans oldans term e sum
)
1958 (unless (> (car x
) 0)
1959 (merror (intl:gettext
"fplog: argument must be positive; found: ~M") (car x
)))
1961 over
(fpquotient (fpone) e
)
1963 ;; Scale X until 1/e < X <= E. ANS keeps track of how
1964 ;; many factors of E were used. Set X to NIL if X is E.
1967 (cond ((equal x e
) (setq x nil
) (return nil
))
1968 ((and (fplessp x e
) (fplessp over x
))
1971 (setq x
(fptimes* x e
))
1975 (setq x
(fpquotient x e
)))))
1976 (when (null x
) (return (intofp (1+ ans
))))
1977 ;; Prepare X for the series. The series is for 1 + x, so
1978 ;; get x from our X. TERM is (x/(x+2)). X becomes
1980 (setq x
(fpdifference x
(fpone))
1982 (setq x
(fpexpt (setq term
(fpquotient x
(fpplus x
(setq two
(intofp 2))))) 2))
1983 ;; Sum the series until the sum (in ANS) doesn't change
1985 (setq sum
(intofp 0))
1987 ((equal sum oldans
))
1989 (setq sum
(fpplus sum
(fpquotient term
(intofp n
))))
1990 (setq term
(fptimes* term x
)))
1991 (return (fpplus ans
(fptimes* two sum
)))))
1993 (defun mabsbigfloat (l)
1995 (setq r
(bigfloatp (car l
)))
1996 (return (if (null r
)
1997 (list '(mabs) (car l
))
1998 (bcons (fpabs (cdr r
)))))))
2001 ;;;; Bigfloat implementations of special functions.
2004 ;;; This is still a bit messy. Some functions here take bigfloat
2005 ;;; numbers, represented by ((bigfloat) <mant> <exp>), but others want
2006 ;;; just the FP number, represented by (<mant> <exp>). Likewise, some
2007 ;;; return a bigfloat, some return just the FP.
2009 ;;; This needs to be systemized somehow. It isn't helped by the fact
2010 ;;; that some of the routines above also do the samething.
2012 ;;; The implementation for the special functions for a complex
2013 ;;; argument are mostly taken from W. Kahan, "Branch Cuts for Complex
2014 ;;; Elementary Functions or Much Ado About Nothing's Sign Bit", in
2015 ;;; Iserles and Powell (eds.) "The State of the Art in Numerical
2016 ;;; Analysis", pp 165-211, Clarendon Press, 1987
2018 ;; Compute exp(x) - 1, but do it carefully to preserve precision when
2019 ;; |x| is small. X is a FP number, and a FP number is returned. That
2020 ;; is, no bigfloat stuff.
2022 ;; What is the right breakpoint here? Is 1 ok? Perhaps 1/e is better?
2023 (cond ((fpgreaterp (fpabs x
) (fpone))
2025 (fpdifference (fpexp x
) (fpone)))
2027 ;; Use Taylor series for exp(x) - 1
2033 (setf term
(fpquotient (fptimes* x term
) (intofp n
)))
2035 (setf ans
(fpplus ans term
)))
2038 ;; log(1+x) for small x. X is FP number, and a FP number is returned.
2040 ;; Use the same series as given above for fplog. For small x we use
2041 ;; the series, otherwise fplog is accurate enough.
2042 (cond ((fpgreaterp (fpabs x
) (fpone))
2043 (fplog (fpplus x
(fpone))))
2045 (let* ((sum (intofp 0))
2046 (term (fpquotient x
(fpplus x
(intofp 2))))
2047 (f (fptimes* term term
))
2050 ((equal sum oldans
))
2052 (setq sum
(fpplus sum
(fpquotient term
(intofp n
))))
2053 (setq term
(fptimes* term f
)))
2054 (fptimes* sum
(intofp 2))))))
2056 ;; sinh(x) for real x. X is a bigfloat, and a bigfloat is returned.
2058 ;; X must be a maxima bigfloat
2060 ;; See, for example, Hart et al., Computer Approximations, 6.2.27:
2062 ;; sinh(x) = 1/2*(D(x) + D(x)/(1+D(x)))
2064 ;; where D(x) = exp(x) - 1.
2066 ;; But for negative x, use sinh(x) = -sinh(-x) because D(x)
2067 ;; approaches -1 for large negative x.
2068 (cond ((equal 0 (cadr x
))
2069 ;; Special case: x=0. Return immediately.
2073 (let ((d (fpexpm1 (cdr (bigfloatp x
)))))
2074 (bcons (fpquotient (fpplus d
(fpquotient d
(fpplus d
(fpone))))
2079 (fpminus (cdr (fpsinh (bcons (fpminus (cdr (bigfloatp x
)))))))))))
2081 (defun big-float-sinh (x &optional y
)
2082 ;; The rectform for sinh for complex args should be numerically
2083 ;; accurate, so return nil in that case.
2087 ;; asinh(x) for real x. X is a bigfloat, and a bigfloat is returned.
2089 ;; asinh(x) = sign(x) * log(|x| + sqrt(1+x*x))
2093 ;; asinh(x) = x, if 1+x*x = 1
2094 ;; = sign(x) * (log(2) + log(x)), large |x|
2095 ;; = sign(x) * log(2*|x| + 1/(|x|+sqrt(1+x*x))), if |x| > 2
2096 ;; = sign(x) * log1p(|x|+x^2/(1+sqrt(1+x*x))), otherwise.
2098 ;; But I'm lazy right now and we only implement the last 2 cases.
2099 ;; We should implement all cases.
2100 (let* ((fp-x (cdr (bigfloatp x
)))
2104 (minus (minusp (car fp-x
)))
2106 ;; We only use two formulas here. |x| <= 2 and |x| > 2. Should
2107 ;; we add one for very big x and one for very small x, as given above.
2108 (cond ((fpgreaterp absx two
)
2111 ;; log(2*|x| + 1/(|x|+sqrt(1+x^2)))
2112 (setf result
(fplog (fpplus (fptimes* absx two
)
2115 (fproot (bcons (fpplus one
2116 (fptimes* absx absx
)))
2121 ;; log1p(|x|+x^2/(1+sqrt(1+x^2)))
2122 (let ((x*x
(fptimes* absx absx
)))
2123 (setq result
(fplog1p (fpplus absx
2126 (fproot (bcons (fpplus one x
*x
))
2129 (bcons (fpminus result
))
2132 (defun complex-asinh (x y
)
2133 ;; asinh(z) = -%i * asin(%i*z)
2134 (multiple-value-bind (u v
)
2135 (complex-asin (mul -
1 y
) x
)
2136 (values v
(bcons (fpminus (cdr u
))))))
2138 (defun big-float-asinh (x &optional y
)
2140 (multiple-value-bind (u v
)
2142 (add u
(mul '$%i v
)))
2145 (defun fpasin-core (x)
2146 ;; asin(x) = atan(x/(sqrt(1-x^2))
2147 ;; = sgn(x)*[%pi/2 - atan(sqrt(1-x^2)/abs(x))]
2149 ;; Use the first for 0 <= x < 1/2 and the latter for 1/2 < x <= 1.
2151 ;; If |x| > 1, we need to do something else.
2153 ;; asin(x) = -%i*log(sqrt(1-x^2)+%i*x)
2154 ;; = -%i*log(%i*x + %i*sqrt(x^2-1))
2155 ;; = -%i*[log(|x + sqrt(x^2-1)|) + %i*%pi/2]
2156 ;; = %pi/2 - %i*log(|x+sqrt(x^2-1)|)
2158 (let ((fp-x (cdr (bigfloatp x
))))
2159 (cond ((minusp (car fp-x
))
2160 ;; asin(-x) = -asin(x);
2161 (mul -
1 (fpasin (bcons (fpminus fp-x
)))))
2162 ((fplessp fp-x
(cdr bfhalf
))
2164 ;; asin(x) = atan(x/sqrt(1-x^2))
2166 (fpatan (fpquotient fp-x
2168 (fptimes* (fpdifference (fpone) fp-x
)
2169 (fpplus (fpone) fp-x
)))
2171 ((fpgreaterp fp-x
(fpone))
2173 ;; asin(x) = %pi/2 - %i*log(|x+sqrt(x^2-1)|)
2175 ;; Should we try to do something a little fancier with the
2176 ;; argument to log and use log1p for better accuracy?
2177 (let ((arg (fpplus fp-x
2178 (fproot (bcons (fptimes* (fpdifference fp-x
(fpone))
2179 (fpplus fp-x
(fpone))))
2182 (mul -
1 '$%i
(bcons (fplog arg
))))))
2186 ;; asin(x) = %pi/2 - atan(sqrt(1-x^2)/x)
2191 (fpquotient (fproot (bcons (fptimes* (fpdifference (fpone) fp-x
)
2192 (fpplus (fpone) fp-x
)))
2196 ;; asin(x) for real x. X is a bigfloat, and a maxima number (real or
2197 ;; complex) is returned.
2199 ;; asin(x) = atan(x/(sqrt(1-x^2))
2200 ;; = sgn(x)*[%pi/2 - atan(sqrt(1-x^2)/abs(x))]
2202 ;; Use the first for 0 <= x < 1/2 and the latter for 1/2 < x <= 1.
2204 ;; If |x| > 1, we need to do something else.
2206 ;; asin(x) = -%i*log(sqrt(1-x^2)+%i*x)
2207 ;; = -%i*log(%i*x + %i*sqrt(x^2-1))
2208 ;; = -%i*[log(|x + sqrt(x^2-1)|) + %i*%pi/2]
2209 ;; = %pi/2 - %i*log(|x+sqrt(x^2-1)|)
2211 ($bfloat
(fpasin-core x
)))
2213 ;; Square root of a complex number (xx, yy). Both are bigfloats. FP
2214 ;; (non-bigfloat) numbers are returned.
2215 (defun complex-sqrt (xx yy
)
2216 (let* ((x (cdr (bigfloatp xx
)))
2217 (y (cdr (bigfloatp yy
)))
2218 (rho (fpplus (fptimes* x x
)
2220 (setf rho
(fpplus (fpabs x
) (fproot (bcons rho
) 2)))
2221 (setf rho
(fpplus rho rho
))
2222 (setf rho
(fpquotient (fproot (bcons rho
) 2) (intofp 2)))
2226 (when (fpgreaterp rho
(intofp 0))
2227 (setf nu
(fpquotient (fpquotient nu rho
) (intofp 2)))
2228 (when (fplessp x
(intofp 0))
2229 (setf eta
(fpabs nu
))
2230 (setf nu
(if (minusp (car y
))
2235 ;; asin(z) for complex z = x + %i*y. X and Y are bigfloats. The real
2236 ;; and imaginary parts are returned as bigfloat numbers.
2237 (defun complex-asin (x y
)
2238 (let ((x (cdr (bigfloatp x
)))
2239 (y (cdr (bigfloatp y
))))
2240 (multiple-value-bind (re-sqrt-1-z im-sqrt-1-z
)
2241 (complex-sqrt (bcons (fpdifference (intofp 1) x
))
2242 (bcons (fpminus y
)))
2243 (multiple-value-bind (re-sqrt-1+z im-sqrt-1
+z
)
2244 (complex-sqrt (bcons (fpplus (intofp 1) x
))
2246 ;; Realpart is atan(x/Re(sqrt(1-z)*sqrt(1+z)))
2247 ;; Imagpart is asinh(Im(conj(sqrt(1-z))*sqrt(1+z)))
2249 (let ((d (fpdifference (fptimes* re-sqrt-1-z
2251 (fptimes* im-sqrt-1-z
2253 ;; Check for division by zero. If we would divide
2254 ;; by zero, return pi/2 or -pi/2 according to the
2256 (cond ((equal d
'(0 0))
2257 (if (fplessp x
'(0 0))
2258 (fpminus (fpquotient (fppi) (intofp 2)))
2259 (fpquotient (fppi) (intofp 2))))
2261 (fpatan (fpquotient x d
))))))
2263 (fpdifference (fptimes* re-sqrt-1-z
2265 (fptimes* im-sqrt-1-z
2266 re-sqrt-1
+z
)))))))))
2268 (defun big-float-asin (x &optional y
)
2270 (multiple-value-bind (u v
) (complex-asin x y
)
2271 (add u
(mul '$%i v
)))
2275 ;; tanh(x) for real x. X is a bigfloat, and a bigfloat is returned.
2277 ;; X is Maxima bigfloat
2278 ;; tanh(x) = D(2*x)/(2+D(2*x))
2279 (let* ((two (intofp 2))
2280 (fp (cdr (bigfloatp x
)))
2281 (d (fpexpm1 (fptimes* fp two
))))
2282 (bcons (fpquotient d
(fpplus d two
)))))
2284 ;; tanh(z), z = x + %i*y. X, Y are bigfloats, and a maxima number is
2286 (defun complex-tanh (x y
)
2287 (let* ((tv (cdr (tanbigfloat (list y
))))
2288 (beta (fpplus (fpone) (fptimes* tv tv
)))
2289 (s (cdr (fpsinh x
)))
2290 (s^
2 (fptimes* s s
))
2291 (rho (fproot (bcons (fpplus (fpone) s^
2)) 2))
2292 (den (fpplus (fpone) (fptimes* beta s^
2))))
2293 (values (bcons (fpquotient (fptimes* beta
(fptimes* rho s
)) den
))
2294 (bcons (fpquotient tv den
)))))
2296 (defun big-float-tanh (x &optional y
)
2298 (multiple-value-bind (u v
) (complex-tanh x y
)
2299 (add u
(mul '$%i v
)))
2302 ;; atanh(x) for real x, |x| <= 1. X is a bigfloat, and a bigfloat is
2305 ;; atanh(x) = -atanh(-x)
2306 ;; = 1/2*log1p(2*x/(1-x)), x >= 0.5
2307 ;; = 1/2*log1p(2*x+2*x*x/(1-x)), x <= 0.5
2309 (let* ((fp-x (cdr (bigfloatp x
))))
2310 (cond ((fplessp fp-x
(intofp 0))
2311 ;; atanh(x) = -atanh(-x)
2312 (mul -
1 (fpatanh (bcons (fpminus fp-x
)))))
2313 ((fpgreaterp fp-x
(fpone))
2314 ;; x > 1, so use complex version.
2315 (multiple-value-bind (u v
)
2316 (complex-atanh x
(bcons (intofp 0)))
2317 (add u
(mul '$%i v
))))
2318 ((fpgreaterp fp-x
(cdr bfhalf
))
2319 ;; atanh(x) = 1/2*log1p(2*x/(1-x))
2321 (fptimes* (cdr bfhalf
)
2322 (fplog1p (fpquotient (fptimes* (intofp 2) fp-x
)
2323 (fpdifference (fpone) fp-x
))))))
2325 ;; atanh(x) = 1/2*log1p(2*x + 2*x*x/(1-x))
2326 (let ((2x (fptimes* (intofp 2) fp-x
)))
2328 (fptimes* (cdr bfhalf
)
2330 (fpquotient (fptimes* 2x fp-x
)
2331 (fpdifference (fpone) fp-x
)))))))))))
2333 ;; Stuff which follows is derived from atanh z = (log(1 + z) - log(1 - z))/2
2334 ;; which apparently originates with Kahan's "Much ado" paper.
2336 ;; The formulas for eta and nu below can be easily derived from
2337 ;; rectform(atanh(x+%i*y)) =
2339 ;; 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)))
2341 ;; Expand the argument of log out and divide it out and we get
2343 ;; log(((1+x)^2+y^2)/((1-x)^2+y^2)) = log(1+4*x/((1-x)^2+y^2))
2345 ;; When y = 0, Im atanh z = 1/2 (arg(1 + x) - arg(1 - x))
2346 ;; = if x < -1 then %pi/2 else if x > 1 then -%pi/2 else 0
2348 ;; Otherwise, arg(1 - x + %i*(-y)) = - arg(1 - x + %i*y),
2349 ;; and Im atanh z = 1/2 (arg(1 + x + %i*y) + arg(1 - x + %i*y)).
2350 ;; Since arg(x)+arg(y) = arg(x*y) (almost), we can simplify the
2351 ;; imaginary part to
2353 ;; arg((1+x+%i*y)*(1-x+%i*y)) = arg((1-x)*(1+x)-y^2+2*y*%i)
2354 ;; = atan2(2*y,((1-x)*(1+x)-y^2))
2356 ;; These are the eta and nu forms below.
2357 (defun complex-atanh (x y
)
2358 (let* ((fpx (cdr (bigfloatp x
)))
2359 (fpy (cdr (bigfloatp y
)))
2360 (beta (if (minusp (car fpx
))
2363 (x-lt-minus-1 (mevalp `((mlessp) ,x -
1)))
2364 (x-gt-plus-1 (mevalp `((mgreaterp) ,x
1)))
2365 (y-equals-0 (like y
'((bigfloat) 0 0)))
2366 (x (fptimes* beta fpx
))
2367 (y (fptimes* beta
(fpminus fpy
)))
2368 ;; Kahan has rho = 4/most-positive-float. What should we do
2369 ;; here about that? Our big floats don't really have a
2370 ;; most-positive float value.
2372 (t1 (fpplus (fpabs y
) rho
))
2373 (t1^
2 (fptimes* t1 t1
))
2374 (1-x (fpdifference (fpone) x
))
2375 ;; eta = log(1+4*x/((1-x)^2+y^2))/4
2377 (fplog1p (fpquotient (fptimes* (intofp 4) x
)
2378 (fpplus (fptimes* 1-x
1-x
)
2381 ;; If y = 0, then Im atanh z = %pi/2 or -%pi/2 or 0 depending
2382 ;; on whether x > 1, x < -1 or |x| <=1, respectively.
2384 ;; Otherwise nu = 1/2*atan2(2*y,(1-x)*(1+x)-y^2)
2386 ;; Extra fpminus here to counteract fpminus in return
2387 ;; value because we don't support signed zeroes.
2388 (fpminus (if x-lt-minus-1
2389 (cdr ($bfloat
'((mquotient) $%pi
2)))
2391 (cdr ($bfloat
'((mminus) ((mquotient) $%pi
2))))
2393 (fptimes* (cdr bfhalf
)
2394 (fpatan2 (fptimes* (intofp 2) y
)
2395 (fpdifference (fptimes* 1-x
(fpplus (fpone) x
))
2397 (values (bcons (fptimes* beta eta
))
2398 ;; Minus sign here because Kahan's algorithm assumed
2399 ;; signed zeroes, which we don't have in maxima.
2400 (bcons (fpminus (fptimes* beta nu
))))))
2402 (defun big-float-atanh (x &optional y
)
2404 (multiple-value-bind (u v
) (complex-atanh x y
)
2405 (add u
(mul '$%i v
)))
2408 ;; acos(x) for real x. X is a bigfloat, and a maxima number is returned.
2410 ;; acos(x) = %pi/2 - asin(x)
2411 ($bfloat
(add (div '$%pi
2) (mul -
1 (fpasin-core x
)))))
2413 (defun complex-acos (x y
)
2414 (let ((x (cdr (bigfloatp x
)))
2415 (y (cdr (bigfloatp y
))))
2416 (multiple-value-bind (re-sqrt-1-z im-sqrt-1-z
)
2417 (complex-sqrt (bcons (fpdifference (intofp 1) x
))
2418 (bcons (fpminus y
)))
2419 (multiple-value-bind (re-sqrt-1+z im-sqrt-1
+z
)
2420 (complex-sqrt (bcons (fpplus (intofp 1) x
))
2423 (fptimes* (intofp 2)
2424 (fpatan (fpquotient re-sqrt-1-z re-sqrt-1
+z
))))
2427 (fptimes* re-sqrt-1
+z im-sqrt-1-z
)
2428 (fptimes* im-sqrt-1
+z re-sqrt-1-z
)))))))))
2431 (defun big-float-acos (x &optional y
)
2433 (multiple-value-bind (u v
) (complex-acos x y
)
2434 (add u
(mul '$%i v
)))
2437 (defun complex-log (x y
)
2438 (let* ((x (cdr (bigfloatp x
)))
2439 (y (cdr (bigfloatp y
)))
2440 (t1 (let (($float2bf t
))
2441 ;; No warning message, please.
2444 (rho (fpplus (fptimes* x x
)
2448 (beta (fpmax abs-x abs-y
))
2449 (theta (fpmin abs-x abs-y
)))
2450 (values (if (or (fpgreaterp t1 beta
)
2452 (fpquotient (fplog1p (fpplus (fptimes* (fpdifference beta
(fpone))
2453 (fpplus beta
(fpone)))
2454 (fptimes* theta theta
)))
2456 (fpquotient (fplog rho
) (intofp 2)))
2459 (defun big-float-log (x &optional y
)
2461 (multiple-value-bind (u v
) (complex-log x y
)
2462 (add (bcons u
) (mul '$%i
(bcons v
))))
2464 ;; x is (mantissa exp), where mantissa = frac*2^fpprec,
2465 ;; with 1/2 < frac <= 1 and x is frac*2^exp. To
2466 ;; compute log(x), use log(x) = log(frac)+ exp*log(2).
2469 (fpprec (+ fpprec extra
))
2473 (cl-rat-to-maxima (/ (car x
)
2474 (ash 1 (- fpprec
8))))))
2475 (list (ash (car x
) extra
) 0)))
2476 (log-exp (fptimes* (intofp (second x
)) (fplog2)))
2477 (result (bcons (fpplus log-frac log-exp
))))
2478 (let ((fpprec (- fpprec extra
)))
2479 (bigfloatp result
))))))
2480 (let ((fp-x (cdr (bigfloatp x
))))
2482 ;; Special case for log(1). See:
2483 ;; https://sourceforge.net/p/maxima/bugs/2240/
2485 ((fplessp fp-x
(intofp 0))
2486 ;; ??? Do we want to return an exact %i*%pi or a float
2488 (add (big-float-log (bcons (fpminus fp-x
)))
2489 (mul '$%i
(bcons (fppi)))))
2491 (bcons (%log fp-x
))))))))
2493 (defun big-float-sqrt (x &optional y
)
2495 (multiple-value-bind (u v
) (complex-sqrt x y
)
2496 (add (bcons u
) (mul '$%i
(bcons v
))))
2497 (let ((fp-x (cdr (bigfloatp x
))))
2498 (if (fplessp fp-x
(intofp 0))
2499 (mul '$%i
(bcons (fproot (bcons (fpminus fp-x
)) 2)))
2500 (bcons (fproot x
2))))))
2503 (:load-toplevel
:execute
)
2504 (fpprec1 nil $fpprec
)) ; Set up user's precision