1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10-*- ;;;;
3 ;;; This package contains a numeric class for use with Maxima. The
4 ;;; purpose is to allow users to write numerical algorithms that
5 ;;; support double-float, (complex double-float) and Maxima bfloat and
6 ;;; complex bfloat arithmetic, without having to write separate
7 ;;; versions for each. Of course, specially written versions for
8 ;;; double-float and (complex double-float) will probably be much
9 ;;; faster, but this allows users to write just one routine that can
10 ;;; handle all of the data types in a more "natural" Lisp style.
13 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
14 (setf lisp
::*enable-package-locked-errors
* nil
))
16 (in-package #:bigfloat
)
19 ;; Kind of like Maxima's INTOFP, but we only handle numeric types.
20 ;; We should return a Maxima bigfloat object (list of bigfloat
21 ;; marker, mantissa, and exponent).
23 (maxima::bcons
(maxima::floattofp re
)))
25 (maxima::bcons
'(0 0)))
27 (maxima::bcons
(list (maxima::fpround re
) (cl:+ maxima
::*m maxima
::fpprec
))))
29 ;; Should we do something better than converting the
30 ;; numerator and denominator to floats and dividing?
31 (maxima::bcons
(maxima::fpquotient
(cdr (intofp (numerator re
)))
32 (cdr (intofp (denominator re
))))))
33 ((maxima::$bfloatp re
)
34 ;; Call bigfloatp to make sure we round/scale the bigfloat to
35 ;; the correct precision!
36 (maxima::bigfloatp re
))
38 (error "Don't know how to convert ~S to a BIGFLOAT" re
))))
42 (:documentation
"Basic class, like CL's NUMBER type"))
44 (defclass bigfloat
(numeric)
45 ;; We store the Maxima internal bigfloat format because we also need
46 ;; the precision in case we have mixed size bigfloat operations.
47 ;; (We could recompute it from the size of the mantissa part, but
49 ((real :initform
(intofp 0)
51 :documentation
"A Maxima bigfloat. This contains the full
52 Maxima bigfloat object including the mantissa, the exponent
53 and the bigfloat marker and precision." ))
54 (:documentation
"Big float, equivalent to a Maxima bfloat object"))
56 ;; Extract the internal representation of a bigfloat, and adjust the
57 ;; precision to the current value of fpprec.
58 (defmethod real-value ((b bigfloat
))
59 (maxima::bigfloatp
(slot-value b
'real
)))
61 (defclass complex-bigfloat
(numeric)
62 ;; Currently, the real and imaginary parts contain a Maxima bigfloat
63 ;; including the bigfloat marker and the mantissa and exponent.
64 ;; Should they be BIGFLOAT objects instead?
65 ((real :initform
(intofp 0)
67 :documentation
"Real part of a complex bigfloat")
68 (imag :initform
(intofp 0)
70 :documentation
"Imaginary part of a complex bigfloat"))
71 (:documentation
"Complex bigfloat"))
73 ;; Extract the internal representation of the real part of a
74 ;; complex-bigfloat, and adjust the precision to the current value of
76 (defmethod real-value ((b complex-bigfloat
))
77 (maxima::bigfloatp
(slot-value b
'real
)))
79 ;; Extract the internal representation of the imaginary part of a
80 ;; complex-bigfloat, and adjust the precision to the current value of
82 (defmethod imag-value ((b complex-bigfloat
))
83 (maxima::bigfloatp
(slot-value b
'imag
)))
85 (defmethod make-load-form ((x bigfloat
) &optional environment
)
86 (declare (ignore environment
))
87 `(make-instance ',(class-of x
)
88 :real
',(real-value x
)))
90 ;;; BIGFLOAT - External
92 ;;; BIGFLOAT converts a number to a BIGFLOAT or COMPLEX-BIGFLOAT.
93 ;;; This is intended to convert CL numbers or Maxima (internal)
94 ;;; numbers to a bigfloat object.
95 (defun bigfloat (re &optional im
)
96 "Convert RE to a BIGFLOAT. If IM is given, return a COMPLEX-BIGFLOAT"
98 (make-instance 'complex-bigfloat
102 (make-instance 'bigfloat
:real
(intofp re
)))
104 (make-instance 'complex-bigfloat
105 :real
(intofp (cl:realpart re
))
106 :imag
(intofp (cl:imagpart re
))))
107 ((maxima::$bfloatp re
)
108 (make-instance 'bigfloat
:real
(intofp re
)))
109 ((maxima::complex-number-p re
'maxima
::bigfloat-or-number-p
)
110 (make-instance 'complex-bigfloat
111 :real
(intofp (maxima::$realpart re
))
112 :imag
(intofp (maxima::$imagpart re
))))
113 ((typep re
'bigfloat
)
114 ;; Done this way so the new bigfloat updates the precision of
115 ;; the given bigfloat, if necessary.
116 (make-instance 'bigfloat
:real
(real-value re
)))
117 ((typep re
'complex-bigfloat
)
118 ;; Done this way so the new bigfloat updates the precision of
119 ;; the given bigfloat, if necessary.
120 (make-instance 'complex-bigfloat
121 :real
(real-value re
)
122 :imag
(imag-value re
)))
124 (make-instance 'bigfloat
:real
(intofp re
)))))
127 ;;; MAXIMA::TO - External
129 ;;; Convert a CL number, a BIGFLOAT, or a COMPLEX-BIGFLOAT to
130 ;;; Maxima's internal representation of the number.
131 (defmethod maxima::to
((z cl
:float
))
134 (defmethod maxima::to
((z cl
:rational
))
136 (list '(maxima::rat maxima
::simp
) (numerator z
) (denominator z
))
139 (defmethod maxima::to
((z cl
:complex
))
140 (maxima::add
(maxima::to
(cl:realpart z
))
141 (maxima::mul
'maxima
::$%i
142 (maxima::to
(cl:imagpart z
)))))
144 (defmethod maxima::to
((z bigfloat
))
145 "Convert BIGFLOAT object to a maxima number"
148 (defmethod maxima::to
((z complex-bigfloat
))
149 "Convert COMPLEX-BIGFLOAT object to a maxima number"
150 (maxima::add
(real-value z
)
151 (maxima::mul
'maxima
::$%i
154 (defmethod maxima::to
((z t
))
157 ;; MAX-EXPONENT roughly computes the log2(|x|). If x is real and x =
158 ;; 2^n*f, with |f| < 1, MAX-EXPONENT returns |n|. For complex
159 ;; numbers, we return one more than the max of the exponent of the
160 ;; real and imaginary parts.
161 (defmethod max-exponent ((x bigfloat
))
162 ;; The third element is the exponent of a bigfloat.
163 (cl:abs
(third (slot-value x
'real
))))
165 (defmethod max-exponent ((x complex-bigfloat
))
166 (cl:1+ (cl:max
(cl:abs
(third (slot-value x
'real
)))
167 (cl:abs
(third (slot-value x
'imag
))))))
169 (defmethod max-exponent ((x cl
:float
))
172 (cl:abs
(nth-value 1 (cl:decode-float x
)))))
174 (defmethod max-exponent ((x cl
:rational
))
177 (cl:ceiling
(cl:log
(cl:abs x
) 2))))
179 (defmethod max-exponent ((x cl
:complex
))
180 (cl:1+ (cl:max
(max-exponent (cl:realpart x
))
181 (max-exponent (cl:imagpart x
)))))
183 ;; When computing x^a using exp(a*log(x)), we need extra bits because
184 ;; the integer part of a*log(x) doesn't contribute to the accuracy of
185 ;; the result. The number of extra bits needed is basically the
186 ;; "size" of a plus the number of bits for ceiling(log(x)). We need
187 ;; ceiling(log(x)) extra bits because that's how many bits are taken
188 ;; up by the log(x). The "size" of a is, basically, the exponent of
189 ;; a. If a = 2^n*f where |f| < 1, then the size is abs(n) because
190 ;; that's how many extra bits are added to the integer part of
191 ;; a*log(x). If either |x| or |a| < 1, the size is 0, since no
192 ;; additional bits are taken up.
193 (defun expt-extra-bits (x a
)
194 (max 1 (+ (integer-length (max-exponent x
))
197 ;;; WITH-EXTRA-PRECISION - Internal
199 ;;; Executes the body BODY with extra precision. The precision is
200 ;;; increased by EXTRA, and the list of variables given in VARLIST have
201 ;;; the precision increased. The precision of the first value of the
202 ;;; body is then reduced back to the normal precision.
203 (defmacro with-extra-precision
((extra (&rest varlist
)) &body body
)
204 (let ((result (gensym))
205 (old-fpprec (gensym)))
207 (let ((,old-fpprec maxima
::fpprec
))
209 (let ((maxima::fpprec
(cl:+ maxima
::fpprec
,extra
)))
210 (let ,(mapcar #'(lambda (v)
211 ;; Could probably do this in a faster
212 ;; way, but conversion to a maxima
213 ;; form automatically increases the
214 ;; precision of the bigfloat to the
215 ;; new precision. Conversion of that
216 ;; to a bigfloat object preserves the
218 `(,v
(bigfloat:to
(maxima::to
,v
))))
221 (setf maxima
::fpprec
,old-fpprec
)))))
222 ;; Conversion of the result to a maxima number adjusts the
223 ;; precision appropriately.
224 (bigfloat:to
(maxima::to
,result
)))))
228 (defmethod realp ((x cl
:real
))
231 (defmethod realp ((x bigfloat
))
234 (defmethod realp ((x t
))
238 (defmethod complexp ((x cl
:complex
))
241 (defmethod complexp ((x complex-bigfloat
))
244 (defmethod complexp ((x t
))
248 (defmethod numberp ((x cl
:number
))
251 (defmethod numberp ((x bigfloat
))
254 (defmethod numberp ((x complex-bigfloat
))
257 (defmethod numberp ((x t
))
260 (defmethod make-load-form ((x complex-bigfloat
) &optional environment
)
261 (declare (ignore environment
))
262 `(make-instance ',(class-of x
)
263 :real
',(real-value x
)
264 :imag
',(imag-value x
)))
266 ;; The print-object and describe-object methods are mostly for
267 ;; debugging purposes. Maxima itself shouldn't ever see such objects.
268 (defmethod print-object ((x bigfloat
) stream
)
269 (let ((r (cdr (real-value x
))))
270 (multiple-value-bind (sign output-list
)
271 (if (cl:minusp
(first r
))
272 (values "-" (maxima::fpformat
(maxima::bcons
(list (cl:-
(first r
)) (second r
)))))
273 (values "+" (maxima::fpformat
(maxima::bcons r
))))
274 (format stream
"~A~{~D~}" sign output-list
))))
276 (defmethod print-object ((x complex-bigfloat
) stream
)
277 (format stream
"~A~A*%i" (realpart x
) (imagpart x
)))
279 (defmethod describe-object ((x bigfloat
) stream
)
280 (let ((r (slot-value x
'real
)))
281 (format stream
"~&~S is a ~D-bit BIGFLOAT with mantissa ~D and exponent ~D~%"
282 x
(third (first r
)) (second r
) (third r
))))
284 (defmethod describe-object ((x complex-bigfloat
) stream
)
285 (format stream
"~S is a COMPLEX-BIGFLOAT~%" x
)
286 (describe-object (make-instance 'bigfloat
:real
(slot-value x
'real
)) stream
)
287 (describe-object (make-instance 'bigfloat
:real
(slot-value x
'imag
)) stream
))
291 (:documentation
"Add 1"))
294 (:documentation
"Subtract 1"))
297 (defgeneric two-arg-
+ (a b
)
298 (:documentation
"A + B"))
300 (defgeneric two-arg--
(a b
)
301 (:documentation
"A - B"))
303 (defgeneric two-arg-
* (a b
)
304 (:documentation
"A * B"))
306 (defgeneric two-arg-
/ (a b
)
307 (:documentation
"A / B"))
309 (defgeneric two-arg-
< (a b
)
310 (:documentation
"A < B"))
312 (defgeneric two-arg-
> (a b
)
313 (:documentation
"A > B"))
315 (defgeneric two-arg-
<= (a b
)
316 (:documentation
"A <= B"))
318 (defgeneric two-arg-
>= (a b
)
319 (:documentation
"A >= B"))
321 (defgeneric two-arg-
= (a b
)
322 (:documentation
"A = B?"))
325 (defgeneric unary-minus
(a)
326 (:documentation
"-A"))
328 (defgeneric unary-divide
(a)
329 (:documentation
"1 / A"))
332 ;;; Basic arithmetic operations
336 (defmethod add1 ((a number
))
339 (defmethod add1 ((a bigfloat
))
340 (make-instance 'bigfloat
342 (maxima::fpplus
(cdr (real-value a
))
345 (defmethod add1 ((a complex-bigfloat
))
346 (make-instance 'complex-bigfloat
348 (maxima::fpplus
(cdr (real-value a
))
350 :imag
(imag-value a
)))
352 (defmethod sub1 ((a number
))
355 (defmethod sub1 ((a bigfloat
))
356 (make-instance 'bigfloat
358 (maxima::fpdifference
(cdr (real-value a
))
361 (defmethod sub1 ((a complex-bigfloat
))
362 (make-instance 'complex-bigfloat
364 (maxima::fpdifference
(cdr (real-value a
))
366 :imag
(imag-value a
)))
368 (declaim (inline 1+ 1-
))
377 (defmethod two-arg-+ ((a cl
:number
) (b cl
:number
))
380 (defmethod two-arg-+ ((a bigfloat
) (b bigfloat
))
381 (make-instance 'bigfloat
383 (maxima::fpplus
(cdr (real-value a
))
384 (cdr (real-value b
))))))
386 (defmethod two-arg-+ ((a complex-bigfloat
) (b complex-bigfloat
))
387 (make-instance 'complex-bigfloat
389 (maxima::fpplus
(cdr (real-value a
))
390 (cdr (real-value b
))))
392 (maxima::fpplus
(cdr (imag-value a
))
393 (cdr (imag-value b
))))))
395 ;; Handle contagion for two-arg-+
396 (defmethod two-arg-+ ((a bigfloat
) (b cl
:float
))
397 (make-instance 'bigfloat
399 (maxima::fpplus
(cdr (real-value a
))
402 (defmethod two-arg-+ ((a bigfloat
) (b cl
:rational
))
403 (make-instance 'bigfloat
405 (maxima::fpplus
(cdr (real-value a
))
408 (defmethod two-arg-+ ((a bigfloat
) (b cl
:complex
))
409 (make-instance 'complex-bigfloat
411 (maxima::fpplus
(cdr (real-value a
))
412 (cdr (intofp (realpart b
)))))
413 :imag
(intofp (imagpart b
))))
415 (defmethod two-arg-+ ((a cl
:number
) (b bigfloat
))
418 (defmethod two-arg-+ ((a complex-bigfloat
) (b bigfloat
))
419 (make-instance 'complex-bigfloat
421 (maxima::fpplus
(cdr (real-value a
))
422 (cdr (real-value b
))))
423 :imag
(imag-value a
)))
425 (defmethod two-arg-+ ((a complex-bigfloat
) (b number
))
426 (make-instance 'complex-bigfloat
428 (maxima::fpplus
(cdr (real-value a
))
429 (cdr (intofp (cl:realpart b
)))))
431 (maxima::fpplus
(cdr (imag-value a
))
432 (cdr (intofp (cl:imagpart b
)))))))
434 (defmethod two-arg-+ ((a bigfloat
) (b complex-bigfloat
))
437 (defmethod two-arg-+ ((a number
) (b complex-bigfloat
))
440 (defun + (&rest args
)
443 (do ((args (cdr args
) (cdr args
))
445 (two-arg-+ res
(car args
))))
449 (defmethod unary-minus ((a number
))
452 (defmethod unary-minus ((a bigfloat
))
453 (make-instance 'bigfloat
455 (maxima::fpminus
(cdr (real-value a
))))))
457 (defmethod unary-minus ((a complex-bigfloat
))
458 (make-instance 'complex-bigfloat
460 (maxima::fpminus
(cdr (real-value a
))))
462 (maxima::fpminus
(cdr (imag-value a
))))))
464 ;;; Subtract two numbers
465 (defmethod two-arg-- ((a number
) (b number
))
468 (defmethod two-arg-- ((a bigfloat
) (b bigfloat
))
469 (make-instance 'bigfloat
471 (maxima::fpdifference
(cdr (real-value a
))
472 (cdr (real-value b
))))))
474 (defmethod two-arg-- ((a complex-bigfloat
) (b complex-bigfloat
))
475 (make-instance 'complex-bigfloat
477 (maxima::fpdifference
(cdr (real-value a
))
478 (cdr (real-value b
))))
480 (maxima::fpdifference
(cdr (imag-value a
))
481 (cdr (imag-value b
))))))
483 ;; Handle contagion for two-arg--
484 (defmethod two-arg-- ((a bigfloat
) (b cl
:float
))
485 (make-instance 'bigfloat
487 (maxima::fpdifference
(cdr (real-value a
))
490 (defmethod two-arg-- ((a bigfloat
) (b cl
:rational
))
491 (make-instance 'bigfloat
493 (maxima::fpdifference
(cdr (real-value a
))
496 (defmethod two-arg-- ((a bigfloat
) (b cl
:complex
))
497 (make-instance 'complex-bigfloat
499 (maxima::fpdifference
(cdr (real-value a
))
500 (cdr (intofp (realpart b
)))))
501 :imag
(maxima::bcons
(maxima::fpminus
(cdr (intofp (imagpart b
)))))))
503 (defmethod two-arg-- ((a cl
:float
) (b bigfloat
))
504 (make-instance 'bigfloat
506 (maxima::fpdifference
(cdr (intofp a
))
507 (cdr (real-value b
))))))
509 (defmethod two-arg-- ((a cl
:rational
) (b bigfloat
))
510 (make-instance 'bigfloat
512 (maxima::fpdifference
(cdr (intofp a
))
513 (cdr (real-value b
))))))
515 (defmethod two-arg-- ((a cl
:complex
) (b bigfloat
))
516 (two-arg-- (bigfloat (cl:realpart a
) (cl:imagpart a
)) b
))
518 (defmethod two-arg-- ((a complex-bigfloat
) (b bigfloat
))
519 (make-instance 'complex-bigfloat
521 (maxima::fpdifference
(cdr (real-value a
))
522 (cdr (real-value b
))))
523 :imag
(imag-value a
)))
525 (defmethod two-arg-- ((a complex-bigfloat
) (b number
))
527 (two-arg-- a
(bigfloat (cl:realpart b
) (cl:imagpart b
)))
528 (two-arg-- a
(bigfloat b
))))
530 (defmethod two-arg-- ((a bigfloat
) (b complex-bigfloat
))
531 (make-instance 'complex-bigfloat
533 (maxima::fpdifference
(cdr (real-value a
))
534 (cdr (real-value b
))))
535 :imag
(maxima::bcons
(maxima::fpminus
(cdr (imag-value b
))))))
537 (defmethod two-arg-- ((a number
) (b complex-bigfloat
))
539 (two-arg-- (bigfloat (cl:realpart a
) (cl:imagpart a
))
541 (two-arg-- (bigfloat a
) b
)))
543 (defun - (number &rest more-numbers
)
545 (do ((nlist more-numbers
(cdr nlist
))
547 ((atom nlist
) result
)
548 (declare (list nlist
))
549 (setq result
(two-arg-- result
(car nlist
))))
550 (unary-minus number
)))
552 ;;; Multiply two numbers
553 (defmethod two-arg-* ((a number
) (b number
))
556 (defmethod two-arg-* ((a bigfloat
) (b bigfloat
))
557 (make-instance 'bigfloat
559 (maxima::fptimes
* (cdr (real-value a
))
560 (cdr (real-value b
))))))
562 (defmethod two-arg-* ((a complex-bigfloat
) (b complex-bigfloat
))
563 (let ((a-re (cdr (real-value a
)))
564 (a-im (cdr (imag-value a
)))
565 (b-re (cdr (real-value b
)))
566 (b-im (cdr (imag-value b
))))
567 (make-instance 'complex-bigfloat
569 (maxima::fpdifference
(maxima::fptimes
* a-re b-re
)
570 (maxima::fptimes
* a-im b-im
)))
572 (maxima::fpplus
(maxima::fptimes
* a-re b-im
)
573 (maxima::fptimes
* a-im b-re
))))))
575 ;; Handle contagion for two-arg-*
576 (defmethod two-arg-* ((a bigfloat
) (b cl
:float
))
577 (make-instance 'bigfloat
579 (maxima::fptimes
* (cdr (real-value a
))
582 (defmethod two-arg-* ((a bigfloat
) (b cl
:rational
))
583 (make-instance 'bigfloat
585 (maxima::fptimes
* (cdr (real-value a
))
588 (defmethod two-arg-* ((a bigfloat
) (b cl
:complex
))
589 (make-instance 'complex-bigfloat
591 (maxima::fptimes
* (cdr (real-value a
))
592 (cdr (intofp (realpart b
)))))
594 (maxima::fptimes
* (cdr (real-value a
))
595 (cdr (intofp (imagpart b
)))))))
597 (defmethod two-arg-* ((a cl
:number
) (b bigfloat
))
600 (defmethod two-arg-* ((a complex-bigfloat
) (b bigfloat
))
601 (make-instance 'complex-bigfloat
603 (maxima::fptimes
* (cdr (real-value a
))
604 (cdr (real-value b
))))
606 (maxima::fptimes
* (cdr (imag-value a
))
607 (cdr (real-value b
))))))
609 (defmethod two-arg-* ((a complex-bigfloat
) (b number
))
611 (two-arg-* a
(bigfloat (cl:realpart b
) (cl:imagpart b
)))
612 (two-arg-* a
(bigfloat b
))))
614 (defmethod two-arg-* ((a bigfloat
) (b complex-bigfloat
))
617 (defmethod two-arg-* ((a number
) (b complex-bigfloat
))
620 (defun * (&rest args
)
623 (do ((args (cdr args
) (cdr args
))
625 (two-arg-* res
(car args
))))
628 ;;; Reciprocal of a number
629 (defmethod unary-divide ((a number
))
632 (defmethod unary-divide ((a bigfloat
))
633 (make-instance 'bigfloat
635 (maxima::fpquotient
(maxima::fpone
)
636 (cdr (real-value a
))))))
638 (defmethod unary-divide ((b complex-bigfloat
))
639 ;; Could just call two-arg-/, but let's optimize this a little
640 (let ((a-re (maxima::fpone
))
641 (b-re (cdr (real-value b
)))
642 (b-im (cdr (imag-value b
))))
643 (if (maxima::fpgreaterp
(maxima::fpabs b-re
) (maxima::fpabs b-im
))
644 (let* ((r (maxima::fpquotient b-im b-re
))
645 (dn (maxima::fpplus b-re
(maxima::fptimes
* r b-im
))))
646 (make-instance 'complex-bigfloat
647 :real
(maxima::bcons
(maxima::fpquotient a-re dn
))
649 (maxima::fpquotient
(maxima::fpminus r
)
651 (let* ((r (maxima::fpquotient b-re b-im
))
652 (dn (maxima::fpplus b-im
(maxima::fptimes
* r b-re
))))
653 (make-instance 'complex-bigfloat
654 :real
(maxima::bcons
(maxima::fpquotient r dn
))
656 (maxima::fpquotient
(maxima::fpminus a-re
)
658 ;;; Divide two numbers
659 (defmethod two-arg-/ ((a number
) (b number
))
662 (defmethod two-arg-/ ((a bigfloat
) (b bigfloat
))
663 (make-instance 'bigfloat
665 (maxima::fpquotient
(cdr (real-value a
))
666 (cdr (real-value b
))))))
668 (defmethod two-arg-/ ((a complex-bigfloat
) (b complex-bigfloat
))
669 (let ((a-re (cdr (real-value a
)))
670 (a-im (cdr (imag-value a
)))
671 (b-re (cdr (real-value b
)))
672 (b-im (cdr (imag-value b
))))
673 (if (maxima::fpgreaterp
(maxima::fpabs b-re
) (maxima::fpabs b-im
))
674 (let* ((r (maxima::fpquotient b-im b-re
))
675 (dn (maxima::fpplus b-re
(maxima::fptimes
* r b-im
))))
676 (make-instance 'complex-bigfloat
680 (maxima::fptimes
* a-im r
))
684 (maxima::fpdifference a-im
685 (maxima::fptimes
* a-re r
))
687 (let* ((r (maxima::fpquotient b-re b-im
))
688 (dn (maxima::fpplus b-im
(maxima::fptimes
* r b-re
))))
689 (make-instance 'complex-bigfloat
692 (maxima::fpplus
(maxima::fptimes
* a-re r
)
696 (maxima::fpquotient
(maxima::fpdifference
697 (maxima::fptimes
* a-im r
)
700 ;; Handle contagion for two-arg-/
701 (defmethod two-arg-/ ((a bigfloat
) (b cl
:float
))
702 (make-instance 'bigfloat
704 (maxima::fpquotient
(cdr (real-value a
))
707 (defmethod two-arg-/ ((a bigfloat
) (b cl
:rational
))
708 (make-instance 'bigfloat
710 (maxima::fpquotient
(cdr (real-value a
))
713 (defmethod two-arg-/ ((a bigfloat
) (b cl
:complex
))
714 (two-arg-/ (complex a
) b
))
716 (defmethod two-arg-/ ((a cl
:float
) (b bigfloat
))
717 (make-instance 'bigfloat
719 (maxima::fpquotient
(cdr (intofp a
))
720 (cdr (real-value b
))))))
722 (defmethod two-arg-/ ((a cl
:rational
) (b bigfloat
))
723 (make-instance 'bigfloat
725 (maxima::fpquotient
(cdr (intofp a
))
726 (cdr (real-value b
))))))
728 (defmethod two-arg-/ ((a cl
:complex
) (b bigfloat
))
729 (two-arg-/ (bigfloat a
) b
))
732 (defmethod two-arg-/ ((a complex-bigfloat
) (b bigfloat
))
733 (make-instance 'complex-bigfloat
735 (maxima::fpquotient
(cdr (real-value a
))
736 (cdr (real-value b
))))
738 (maxima::fpquotient
(cdr (imag-value a
))
739 (cdr (real-value b
))))))
741 (defmethod two-arg-/ ((a complex-bigfloat
) (b number
))
743 (two-arg-/ a
(bigfloat (cl:realpart b
) (cl:imagpart b
)))
744 (two-arg-/ a
(bigfloat b
))))
746 (defmethod two-arg-/ ((a bigfloat
) (b complex-bigfloat
))
747 (two-arg-/ (make-instance 'complex-bigfloat
:real
(real-value a
))
750 (defmethod two-arg-/ ((a number
) (b complex-bigfloat
))
752 (two-arg-/ (bigfloat (cl:realpart a
) (cl:imagpart a
))
754 (two-arg-/ (bigfloat a
) b
)))
757 (defun / (number &rest more-numbers
)
759 (do ((nlist more-numbers
(cdr nlist
))
761 ((atom nlist
) result
)
762 (declare (list nlist
))
763 (setq result
(two-arg-/ result
(car nlist
))))
764 (unary-divide number
)))
766 ;;; Compare against zero (zerop, minusp, plusp)
769 (let ((cl-name (intern (symbol-name name
) :cl
)))
771 (defmethod ,name
((x cl
:float
))
773 (defmethod ,name
((x cl
:rational
))
778 (defmethod zerop ((x number
))
781 (defmethod zerop ((x bigfloat
))
782 (let ((r (cdr (real-value x
))))
783 (and (zerop (first r
))
784 (zerop (second r
)))))
786 (defmethod zerop ((a complex-bigfloat
))
787 (and (equal (cdr (real-value a
)) '(0 0))
788 (equal (cdr (imag-value a
)) '(0 0))))
790 (defmethod plusp ((x bigfloat
))
791 (cl:plusp
(first (cdr (real-value x
)))))
793 (defmethod minusp ((x bigfloat
))
794 (cl:minusp
(first (cdr (real-value x
)))))
799 (defmethod two-arg-= ((a number
) (b number
))
802 (defmethod two-arg-= ((a bigfloat
) (b bigfloat
))
803 (zerop (two-arg-- a b
)))
805 (defmethod two-arg-= ((a complex-bigfloat
) (b complex-bigfloat
))
806 (zerop (two-arg-- a b
)))
808 ;; Handle contagion for two-arg-=. This needs some work. CL says
809 ;; floats and rationals are compared by converting the float to a
810 ;; rational before converting.
811 (defmethod two-arg-= ((a bigfloat
) (b number
))
812 (zerop (two-arg-- a b
)))
814 (defmethod two-arg-= ((a number
) (b bigfloat
))
817 (defmethod two-arg-= ((a complex-bigfloat
) (b number
))
818 (zerop (two-arg-- a b
)))
820 (defmethod two-arg-= ((a number
) (b complex-bigfloat
))
823 (defun = (number &rest more-numbers
)
824 "Returns T if all of its arguments are numerically equal, NIL otherwise."
825 (declare (optimize (safety 2))
826 (dynamic-extent more-numbers
))
827 (do ((nlist more-numbers
(cdr nlist
)))
829 (declare (list nlist
))
830 (if (not (two-arg-= (car nlist
) number
))
833 (defun /= (number &rest more-numbers
)
834 "Returns T if no two of its arguments are numerically equal, NIL otherwise."
835 (declare (optimize (safety 2))
836 (dynamic-extent more-numbers
))
837 (do* ((head number
(car nlist
))
838 (nlist more-numbers
(cdr nlist
)))
840 (declare (list nlist
))
841 (unless (do* ((nl nlist
(cdr nl
)))
844 (if (two-arg-= head
(car nl
))
848 ;;; Comparison operations
851 (let ((method (intern (concatenate 'string
854 (cl-fun (find-symbol (symbol-name op
) :cl
)))
856 (defmethod ,method
((a cl
:float
) (b cl
:float
))
858 (defmethod ,method
((a cl
:float
) (b cl
:rational
))
860 (defmethod ,method
((a cl
:rational
) (b cl
:float
))
862 (defmethod ,method
((a cl
:rational
) (b cl
:rational
))
864 (defun ,op
(number &rest more-numbers
)
865 "Returns T if its arguments are in strictly increasing order, NIL otherwise."
866 (declare (optimize (safety 2))
867 (dynamic-extent more-numbers
))
868 (do* ((n number
(car nlist
))
869 (nlist more-numbers
(cdr nlist
)))
871 (declare (list nlist
))
872 (if (not (,method n
(car nlist
))) (return nil
))))))))
878 (defmethod two-arg-< ((x bigfloat
) (y bigfloat
))
879 (maxima::fplessp
(cdr (real-value x
)) (cdr (real-value y
))))
881 (defmethod two-arg-< ((x bigfloat
) (y cl
:float
))
882 (maxima::fplessp
(cdr (real-value x
)) (cdr (intofp y
))))
884 (defmethod two-arg-< ((x bigfloat
) (y cl
:rational
))
885 (maxima::fplessp
(cdr (real-value x
)) (cdr (intofp y
))))
887 (defmethod two-arg-< ((x cl
:float
) (y bigfloat
))
888 (maxima::fplessp
(cdr (intofp x
)) (cdr (real-value y
))))
890 (defmethod two-arg-< ((x cl
:rational
) (y bigfloat
))
891 (maxima::fplessp
(cdr (intofp x
)) (cdr (real-value y
))))
893 (defmethod two-arg-> ((x bigfloat
) (y bigfloat
))
894 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (real-value y
))))
896 (defmethod two-arg-> ((x bigfloat
) (y cl
:float
))
897 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (intofp y
))))
899 (defmethod two-arg-> ((x bigfloat
) (y cl
:rational
))
900 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (intofp y
))))
902 (defmethod two-arg-> ((x cl
:float
) (y bigfloat
))
903 (maxima::fpgreaterp
(cdr (intofp x
)) (cdr (real-value y
))))
905 (defmethod two-arg-> ((x cl
:rational
) (y bigfloat
))
906 (maxima::fpgreaterp
(cdr (intofp x
)) (cdr (real-value y
))))
908 (defmethod two-arg-<= ((x bigfloat
) (y bigfloat
))
909 (or (zerop (two-arg-- x y
))
910 (maxima::fplessp
(cdr (real-value x
)) (cdr (real-value y
)))))
912 (defmethod two-arg-<= ((x bigfloat
) (y cl
:float
))
913 (or (zerop (two-arg-- x y
))
914 (maxima::fplessp
(cdr (real-value x
)) (cdr (intofp y
)))))
916 (defmethod two-arg-<= ((x bigfloat
) (y cl
:rational
))
917 (or (zerop (two-arg-- x y
))
918 (maxima::fplessp
(cdr (real-value x
)) (cdr (intofp y
)))))
920 (defmethod two-arg-<= ((x cl
:float
) (y bigfloat
))
921 (or (zerop (two-arg-- x y
))
922 (maxima::fplessp
(cdr (intofp x
)) (cdr (real-value y
)))))
924 (defmethod two-arg-<= ((x cl
:rational
) (y bigfloat
))
925 (or (zerop (two-arg-- x y
))
926 (maxima::fplessp
(cdr (intofp x
)) (cdr (real-value y
)))))
928 (defmethod two-arg->= ((x bigfloat
) (y bigfloat
))
929 (or (zerop (two-arg-- x y
))
930 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (real-value y
)))))
932 (defmethod two-arg->= ((x bigfloat
) (y cl
:float
))
933 (or (zerop (two-arg-- x y
))
934 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (intofp y
)))))
936 (defmethod two-arg->= ((x bigfloat
) (y cl
:rational
))
937 (or (zerop (two-arg-- x y
))
938 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (intofp y
)))))
940 (defmethod two-arg->= ((x cl
:float
) (y bigfloat
))
941 (or (zerop (two-arg-- x y
))
942 (maxima::fpgreaterp
(cdr (intofp x
)) (cdr (real-value y
)))))
944 (defmethod two-arg->= ((x cl
:rational
) (y bigfloat
))
945 (or (zerop (two-arg-- x y
))
946 (maxima::fpgreaterp
(cdr (intofp x
)) (cdr (real-value y
)))))
948 ;; Need to define incf and decf to call our generic +/- methods.
949 (defmacro incf
(place &optional
(delta 1) &environment env
)
950 "The first argument is some location holding a number. This number is
951 incremented by the second argument, DELTA, which defaults to 1."
952 (multiple-value-bind (dummies vals newval setter getter
)
953 (get-setf-expansion place env
)
955 `(let* (,@(mapcar #'list dummies vals
)
957 (,(car newval
) (+ ,getter
,d
)))
960 (defmacro decf
(place &optional
(delta 1) &environment env
)
961 "The first argument is some location holding a number. This number is
962 decremented by the second argument, DELTA, which defaults to 1."
963 (multiple-value-bind (dummies vals newval setter getter
)
964 (get-setf-expansion place env
)
966 `(let* (,@(mapcar #'list dummies vals
)
968 (,(car newval
) (- ,getter
,d
)))
973 ;;; Special functions for real-valued arguments
976 (let ((cl-name (intern (symbol-name name
) :cl
)))
978 (defmethod ,name
((x number
))
996 (defmethod abs ((x bigfloat
))
997 (make-instance 'bigfloat
998 :real
(maxima::bcons
(maxima::fpabs
(cdr (real-value x
))))))
1000 (defmethod abs ((z complex-bigfloat
))
1001 (let ((x (make-instance 'bigfloat
:real
(real-value z
)))
1002 (y (make-instance 'bigfloat
:real
(imag-value z
))))
1003 ;; Bigfloats don't overflow, so we don't need anything special.
1004 (sqrt (+ (* x x
) (* y y
)))))
1006 (defmethod exp ((x bigfloat
))
1007 (make-instance 'bigfloat
1008 :real
(maxima::bcons
(maxima::fpexp
(cdr (real-value x
))))))
1010 (defmethod sin ((x bigfloat
))
1011 (make-instance 'bigfloat
1012 :real
(maxima::bcons
(maxima::fpsin
(cdr (real-value x
)) t
))))
1014 (defmethod cos ((x bigfloat
))
1015 (make-instance 'bigfloat
1016 :real
(maxima::bcons
(maxima::fpsin
(cdr (real-value x
)) nil
))))
1018 (defmethod tan ((x bigfloat
))
1019 (let ((r (cdr (real-value x
))))
1020 (make-instance 'bigfloat
1021 :real
(maxima::bcons
1022 (maxima::fpquotient
(maxima::fpsin r t
)
1023 (maxima::fpsin r nil
))))))
1025 (defmethod asin ((x bigfloat
))
1026 (bigfloat (maxima::fpasin
(real-value x
))))
1028 (defmethod acos ((x bigfloat
))
1029 (bigfloat (maxima::fpacos
(real-value x
))))
1032 (defmethod sqrt ((x bigfloat
))
1034 (make-instance 'complex-bigfloat
1036 :imag
(maxima::bcons
1037 (maxima::fproot
(maxima::bcons
(maxima::fpabs
(cdr (real-value x
)))) 2)))
1038 (make-instance 'bigfloat
1039 :real
(maxima::bcons
1040 (maxima::fproot
(real-value x
) 2)))))
1042 (defmethod sqrt ((z complex-bigfloat
))
1043 (multiple-value-bind (rx ry
)
1044 (maxima::complex-sqrt
(real-value z
)
1046 (make-instance 'complex-bigfloat
1047 :real
(maxima::bcons rx
)
1048 :imag
(maxima::bcons ry
))))
1050 (defmethod one-arg-log ((a number
))
1053 (defmethod one-arg-log ((a bigfloat
))
1055 (make-instance 'complex-bigfloat
1056 :real
(maxima::bcons
1057 (maxima::fplog
(maxima::fpabs
(cdr (real-value a
)))))
1058 :imag
(maxima::bcons
(maxima::fppi
)))
1059 (make-instance 'bigfloat
1060 :real
(maxima::bcons
(maxima::fplog
(cdr (real-value a
)))))))
1062 (defmethod one-arg-log ((a complex-bigfloat
))
1063 (let* ((res (maxima::big-float-log
(real-value a
)
1067 (defmethod two-arg-log ((a number
) (b number
))
1070 (defmethod two-arg-log ((a numeric
) (b numeric
))
1071 (two-arg-/ (one-arg-log a
) (one-arg-log b
)))
1073 (defmethod two-arg-log ((a numeric
) (b cl
:number
))
1074 (two-arg-/ (one-arg-log a
) (one-arg-log (bigfloat b
))))
1076 (defmethod two-arg-log ((a cl
:number
) (b numeric
))
1077 (two-arg-/ (one-arg-log (bigfloat a
)) (one-arg-log b
)))
1079 (defun log (a &optional b
)
1084 (defmethod sinh ((x bigfloat
))
1085 (let ((r (real-value x
)))
1086 (make-instance 'bigfloat
:real
(maxima::fpsinh r
))))
1088 (defmethod cosh ((x bigfloat
))
1089 (let ((r (real-value x
)))
1090 (make-instance 'bigfloat
:real
(maxima::$bfloat
`((maxima::%cosh
) ,r
)))))
1092 (defmethod tanh ((x bigfloat
))
1093 (let ((r (real-value x
)))
1094 (make-instance 'bigfloat
:real
(maxima::fptanh r
))))
1096 (defmethod asinh ((x bigfloat
))
1097 (let ((r (real-value x
)))
1098 (make-instance 'bigfloat
:real
(maxima::fpasinh r
))))
1100 (defmethod atanh ((x bigfloat
))
1101 (let ((r (maxima::big-float-atanh
(real-value x
))))
1102 (if (maxima::bigfloatp r
)
1103 (make-instance 'bigfloat
:real r
)
1104 (make-instance 'complex-bigfloat
1105 :real
(maxima::$realpart r
)
1106 :imag
(maxima::$imagpart r
)))))
1108 (defmethod acosh ((x bigfloat
))
1109 (let* ((r (real-value x
))
1110 (value (maxima::meval
`((maxima::%acosh maxima
::simp
) ,r
))))
1111 (if (maxima::bigfloatp value
)
1112 (make-instance 'bigfloat
:real value
)
1113 (make-instance 'complex-bigfloat
1114 :real
(maxima::$realpart value
)
1115 :imag
(maxima::$imagpart value
)))))
1117 ;;; Complex arguments
1119 ;;; Special functions for complex args
1121 ((frob (name &optional big-float-op-p
)
1123 (let ((big-op (intern (concatenate 'string
1124 (string '#:big-float-
)
1127 `(defmethod ,name
((a complex-bigfloat
))
1128 (let ((res (,big-op
(real-value a
)
1131 (let ((max-op (intern (concatenate 'string
"$" (string name
)) '#:maxima
)))
1132 `(defmethod ,name
((a complex-bigfloat
))
1133 ;; We should do something better than calling meval
1134 (let* ((arg (maxima::add
(real-value a
)
1135 (maxima::mul
'maxima
::$%i
(imag-value a
))))
1136 (result (maxima::meval
`((,',max-op maxima
::simp
) ,arg
))))
1151 (defmethod one-arg-atan ((a number
))
1154 (defmethod one-arg-atan ((a bigfloat
))
1155 (make-instance 'bigfloat
1156 :real
(maxima::bcons
(maxima::fpatan
(cdr (real-value a
))))))
1158 (defmethod one-arg-atan ((z complex-bigfloat
))
1159 ;; atan(z) = -i * atanh(i*z)
1160 (let* ((iz (complex (- (imagpart z
)) (realpart z
)))
1161 (result (atanh iz
)))
1162 (complex (imagpart result
)
1163 (- (realpart result
)))))
1165 (defmethod two-arg-atan ((a real
) (b real
))
1168 (defmethod two-arg-atan ((a bigfloat
) (b bigfloat
))
1169 (make-instance 'bigfloat
1170 :real
(maxima::bcons
1171 (maxima::fpatan2
(cdr (real-value a
))
1172 (cdr (real-value b
))))))
1174 (defmethod two-arg-atan ((a bigfloat
) (b cl
:float
))
1175 (make-instance 'bigfloat
1176 :real
(maxima::bcons
(maxima::fpatan2
(cdr (real-value a
))
1177 (cdr (intofp b
))))))
1179 (defmethod two-arg-atan ((a bigfloat
) (b cl
:rational
))
1180 (make-instance 'bigfloat
1181 :real
(maxima::bcons
(maxima::fpatan2
(cdr (real-value a
))
1182 (cdr (intofp b
))))))
1184 (defmethod two-arg-atan ((a cl
:float
) (b bigfloat
))
1185 (make-instance 'bigfloat
1186 :real
(maxima::bcons
(maxima::fpatan2
(cdr (intofp a
))
1187 (cdr (real-value b
))))))
1189 (defmethod two-arg-atan ((a cl
:rational
) (b bigfloat
))
1190 (make-instance 'bigfloat
1191 :real
(maxima::bcons
(maxima::fpatan2
(cdr (intofp a
))
1192 (cdr (real-value b
))))))
1194 (defun atan (a &optional b
)
1199 (defmethod scale-float ((a cl
:float
) (n integer
))
1200 (cl:scale-float a n
))
1202 (defmethod scale-float ((a bigfloat
) (n integer
))
1203 (if (cl:zerop
(second (real-value a
)))
1204 (make-instance 'bigfloat
:real
(maxima::bcons
(list 0 0)))
1205 (destructuring-bind (marker mantissa exp
)
1207 (declare (ignore marker
))
1208 (make-instance 'bigfloat
:real
(maxima::bcons
(list mantissa
(+ exp n
)))))))
1212 (let ((cl-name (intern (string name
) '#:cl
)))
1213 `(defmethod ,name
((a number
))
1222 (let ((cl-name (intern (string name
) '#:cl
)))
1223 `(defmethod ,name
((a number
) &optional
(divisor 1))
1224 (,cl-name a divisor
)))))
1235 (defmethod realpart ((a bigfloat
))
1236 (make-instance 'bigfloat
:real
(real-value a
)))
1238 (defmethod realpart ((a complex-bigfloat
))
1239 (make-instance 'bigfloat
:real
(real-value a
)))
1241 (defmethod imagpart ((a bigfloat
))
1242 (make-instance 'bigfloat
:real
(intofp 0)))
1244 (defmethod imagpart ((a complex-bigfloat
))
1245 (make-instance 'bigfloat
:real
(imag-value a
)))
1247 (defmethod conjugate ((a bigfloat
))
1248 (make-instance 'bigfloat
:real
(real-value a
)))
1250 (defmethod conjugate ((a complex-bigfloat
))
1251 (make-instance 'complex-bigfloat
1252 :real
(real-value a
)
1253 :imag
(maxima::bcons
(maxima::fpminus
(cdr (imag-value a
))))))
1255 (defmethod cis ((a cl
:float
))
1258 (defmethod cis ((a cl
:rational
))
1261 (defmethod cis ((a bigfloat
))
1262 (make-instance 'complex-bigfloat
1263 :real
(maxima::bcons
(maxima::fpsin
(cdr (real-value a
)) nil
))
1264 :imag
(maxima::bcons
(maxima::fpsin
(cdr (real-value a
)) t
))))
1266 (defmethod phase ((a bigfloat
))
1267 (let ((r (cdr (real-value a
))))
1268 (if (cl:>= (car r
) 0)
1269 (make-instance 'bigfloat
:real
(maxima::bcons
(list 0 0)))
1270 (make-instance 'bigfloat
:real
(maxima::bcons
(maxima::fppi
))))))
1272 (defmethod phase ((a complex-bigfloat
))
1273 (make-instance 'bigfloat
1274 :real
(maxima::bcons
(maxima::fpatan2
(cdr (imag-value a
))
1275 (cdr (real-value a
))))))
1277 (defun max (number &rest more-numbers
)
1278 "Returns the greatest of its arguments."
1279 (declare (optimize (safety 2)) (type (or real bigfloat
) number
)
1280 (dynamic-extent more-numbers
))
1281 (dolist (real more-numbers
)
1282 (when (> real number
)
1283 (setq number real
)))
1286 (defun min (number &rest more-numbers
)
1287 "Returns the least of its arguments."
1288 (declare (optimize (safety 2)) (type (or real bigfloat
) number
)
1289 (dynamic-extent more-numbers
))
1290 (do ((nlist more-numbers
(cdr nlist
))
1291 (result (the (or real bigfloat
) number
)))
1292 ((null nlist
) (return result
))
1293 (declare (list nlist
))
1294 (if (< (car nlist
) result
)
1295 (setq result
(car nlist
)))))
1297 (defmethod one-arg-complex ((a real
))
1300 (defmethod one-arg-complex ((a bigfloat
))
1301 (make-instance 'complex-bigfloat
1302 :real
(real-value a
)
1305 (defmethod two-arg-complex ((a real
) (b real
))
1308 (defmethod two-arg-complex ((a bigfloat
) (b bigfloat
))
1309 (make-instance 'complex-bigfloat
1310 :real
(real-value a
)
1311 :imag
(real-value b
)))
1313 (defmethod two-arg-complex ((a cl
:float
) (b bigfloat
))
1314 (make-instance 'complex-bigfloat
1316 :imag
(real-value b
)))
1318 (defmethod two-arg-complex ((a cl
:rational
) (b bigfloat
))
1319 (make-instance 'complex-bigfloat
1321 :imag
(real-value b
)))
1323 (defmethod two-arg-complex ((a bigfloat
) (b cl
:float
))
1324 (make-instance 'complex-bigfloat
1325 :real
(real-value a
)
1328 (defmethod two-arg-complex ((a bigfloat
) (b cl
:rational
))
1329 (make-instance 'complex-bigfloat
1330 :real
(real-value a
)
1333 (defun complex (a &optional b
)
1335 (two-arg-complex a b
)
1336 (one-arg-complex a
)))
1338 (defmethod unary-floor ((a bigfloat
))
1339 ;; fpentier truncates to zero, so adjust for negative numbers
1340 (let ((trunc (maxima::fpentier
(real-value a
))))
1342 ;; If the truncated value is the same as the original,
1343 ;; there's nothing to do because A was an integer.
1344 ;; Otherwise, we need to subtract 1 to make it the floor.
1351 (defmethod unary-ffloor ((a bigfloat
))
1352 ;; We can probably do better than converting to an integer and
1353 ;; converting back to a float.
1354 (make-instance 'bigfloat
:real
(intofp (unary-floor a
))))
1356 (defmethod floor ((a bigfloat
) &optional
(divisor 1))
1358 (let ((int (unary-floor a
)))
1359 (values int
(- a int
)))
1360 (let ((q (unary-floor (/ a divisor
))))
1361 (values q
(- a
(* q divisor
))))))
1363 (defmethod ffloor ((a bigfloat
) &optional
(divisor 1))
1365 (let ((int (unary-ffloor a
)))
1366 (values int
(- a int
)))
1367 (let ((q (unary-ffloor (/ a divisor
))))
1368 (values q
(- a
(* q divisor
))))))
1370 (defmethod unary-truncate ((a bigfloat
))
1371 (maxima::fpentier
(real-value a
)))
1373 (defmethod unary-ftruncate ((a bigfloat
))
1374 ;; We can probably do better than converting to an integer and
1375 ;; converting back to a float.
1376 (make-instance 'bigfloat
:real
(intofp (unary-truncate a
))))
1378 (defmethod truncate ((a bigfloat
) &optional
(divisor 1))
1380 (let ((int (unary-truncate a
)))
1381 (values int
(- a int
)))
1382 (let ((q (unary-truncate (/ a divisor
))))
1383 (values q
(- a
(* q divisor
))))))
1385 (defmethod ftruncate ((a bigfloat
) &optional
(divisor 1))
1387 (let ((int (unary-ftruncate a
)))
1388 (values int
(- a int
)))
1389 (let ((q (unary-ftruncate (/ a divisor
))))
1390 (values q
(- a
(* q divisor
))))))
1392 (defmethod unary-ceiling ((a bigfloat
))
1393 ;; fpentier truncates to zero, so adjust for positive numbers.
1395 (maxima::fpentier
(real-value a
))
1396 (maxima::fpentier
(real-value (+ a
1)))))
1398 (defmethod unary-fceiling ((a bigfloat
))
1399 ;; We can probably do better than converting to an integer and
1400 ;; converting back to a float.
1401 (make-instance 'bigfloat
:real
(intofp (unary-ceiling a
))))
1403 (defmethod ceiling ((a bigfloat
) &optional
(divisor 1))
1405 (let ((int (unary-ceiling a
)))
1406 (values int
(- a int
)))
1407 (let ((q (unary-ceiling (/ a divisor
))))
1408 (values q
(- a
(* q divisor
))))))
1410 (defmethod fceiling ((a bigfloat
) &optional
(divisor 1))
1412 (let ((int (unary-fceiling a
)))
1413 (values int
(- a int
)))
1414 (let ((q (unary-fceiling (/ a divisor
))))
1415 (values q
(- a
(* q divisor
))))))
1417 ;; Stolen from CMUCL.
1418 (defmethod round ((a bigfloat
) &optional
(divisor 1))
1419 (multiple-value-bind (tru rem
)
1420 (truncate a divisor
)
1423 (let ((thresh (/ (abs divisor
) 2)))
1424 (cond ((or (> rem thresh
)
1425 (and (= rem thresh
) (oddp tru
)))
1426 (if (minusp divisor
)
1427 (values (- tru
1) (+ rem divisor
))
1428 (values (+ tru
1) (- rem divisor
))))
1429 ((let ((-thresh (- thresh
)))
1431 (and (= rem -thresh
) (oddp tru
))))
1432 (if (minusp divisor
)
1433 (values (+ tru
1) (- rem divisor
))
1434 (values (- tru
1) (+ rem divisor
))))
1435 (t (values tru rem
)))))))
1437 (defmethod fround ((number bigfloat
) &optional
(divisor 1))
1438 "Same as ROUND, but returns first value as a float."
1439 (multiple-value-bind (res rem
)
1440 (round number divisor
)
1441 (values (bigfloat res
) rem
)))
1443 (defmethod expt ((a number
) (b number
))
1446 ;; This needs more work
1447 (defmethod expt ((a numeric
) (b numeric
))
1449 ;; CLHS says if the power is 0, the answer is 1 of the appropriate type.
1450 (if (or (typep a
'complex-bigfloat
)
1451 (typep b
'complex-bigfloat
))
1452 (complex (bigfloat 1))
1454 (cond ((and (zerop a
) (plusp (realpart b
)))
1456 ((and (realp b
) (= b
(truncate b
)))
1457 ;; Use the numeric^number method because it can be much
1458 ;; more accurate when b is an integer.
1459 (expt a
(truncate b
)))
1461 (with-extra-precision ((expt-extra-bits a b
)
1463 (exp (* b
(log a
))))))))
1465 (defmethod expt ((a cl
:number
) (b numeric
))
1467 ;; CLHS says if the power is 0, the answer is 1 of the appropriate type.
1468 (if (or (typep a
'cl
:complex
)
1469 (typep b
'complex-bigfloat
))
1470 (complex (bigfloat 1))
1472 (cond ((and (zerop a
) (plusp (realpart b
)))
1474 ((and (realp b
) (= b
(truncate b
)))
1475 (with-extra-precision ((expt-extra-bits a b
)
1477 (intofp (expt a
(truncate b
)))))
1479 (with-extra-precision ((expt-extra-bits a b
)
1481 (exp (* b
(log (bigfloat a
)))))))))
1483 (defmethod expt ((a numeric
) (b cl
:number
))
1485 ;; CLHS says if the power is 0, the answer is 1 of the appropriate type.
1486 (if (or (typep a
'complex-bigfloat
)
1487 (typep b
'cl
:complex
))
1488 (complex (bigfloat 1))
1490 (if (and (zerop a
) (plusp (realpart b
)))
1492 ;; Handle a few special cases using multiplication.
1502 ((= b -
3) (/ (* a a a
)))
1510 (with-extra-precision ((expt-extra-bits a b
)
1512 (exp (* (bigfloat b
) (log a
)))))))))
1514 ;; Handle a^b a little more carefully because the result is known to
1515 ;; be real when a is real and b is an integer.
1516 (defmethod expt ((a bigfloat
) (b integer
))
1519 ((and (zerop a
) (plusp b
))
1520 ;; 0^b, for positive b
1522 ;; Handle a few special cases using multiplication.
1526 ((eql b -
2) (/ (* a a
)))
1527 ((eql b
3) (* a a a
))
1528 ((eql b -
3) (/ (* a a a
)))
1536 ;; a^b = exp(b*log(|a|) + %i*%pi*b)
1537 ;; = exp(b*log(|a|))*exp(%i*%pi*b)
1538 ;; = (-1)^b*exp(b*log(|a|))
1539 (with-extra-precision ((expt-extra-bits a b
)
1541 (* (exp (* b
(log (abs a
))))
1542 (if (oddp b
) -
1 1))))
1544 (with-extra-precision ((expt-extra-bits a b
)
1546 (exp (* b
(log a
)))))))
1550 ;;; TO takes a maxima number and converts it. Floats remain
1551 ;;; floats, maxima cl:rationals are converted to CL cl:rationals. Maxima
1552 ;;; bigfloats are convert to BIGFLOATS. Maxima complex numbers are
1553 ;;; converted to CL complex numbers or to COMPLEX-BIGFLOAT's.
1554 (defun to (maxima-num &optional imag
)
1555 (let ((result (ignore-errors (%to maxima-num imag
))))
1557 (maxima::merror
(intl:gettext
"BIGFLOAT: unable to convert ~M to a CL or BIGFLOAT number.")
1559 (maxima::add maxima-num
(maxima::mul imag
'maxima
::$%i
))
1562 ;;; MAYBE-TO - External
1564 ;;; Like TO, but if the maxima number can't be converted to a CL
1565 ;;; number or BIGFLOAT, just return the maxima number.
1566 (defun maybe-to (maxima-num &optional imag
)
1567 (let ((result (ignore-errors (%to maxima-num imag
))))
1570 (maxima::add maxima-num imag
)
1573 (defun %to
(maxima-num &optional imag
)
1575 ;; Clisp has a "feature" that (complex rat float) does not
1576 ;; make the both components of the complex number a float.
1577 ;; Sometimes this is nice, but other times it's annoying
1578 ;; because it is non-ANSI behavior. For our code, we really
1579 ;; want both components to be a float.
1581 (complex (to maxima-num
) (to imag
))
1583 (let ((re (to maxima-num
))
1585 (cond ((and (rationalp re
) (floatp im
))
1586 (setf re
(float re im
)))
1587 ((and (rational im
) (floatp re
))
1588 (setf im
(float im re
))))
1591 (cond ((cl:numberp maxima-num
)
1593 ((eq maxima-num
'maxima
::$%i
)
1594 ;; Convert %i to an exact complex cl:rational.
1597 ;; Some kind of maxima number
1598 (cond ((maxima::ratnump maxima-num
)
1599 ;; Maxima cl:rational ((mrat ...) num den)
1600 (/ (second maxima-num
) (third maxima-num
)))
1601 ((maxima::$bfloatp maxima-num
)
1602 (bigfloat maxima-num
))
1603 ((maxima::complex-number-p maxima-num
#'(lambda (x)
1605 (maxima::$bfloatp x
)
1607 (eq (caar x
) 'maxima
::rat
)))))
1608 ;; We have some kind of complex number whose
1609 ;; parts are a cl:real, a bfloat, or a Maxima
1611 (let ((re (maxima::$realpart maxima-num
))
1612 (im (maxima::$imagpart maxima-num
)))
1614 ((or (typep maxima-num
'bigfloat
)
1615 (typep maxima-num
'complex-bigfloat
))
1618 (error "BIGFLOAT: unable to convert to a CL or BIGFLOAT number."))))))
1620 ;;; EPSILON - External
1622 ;;; Return the float epsilon value for the given float type.
1623 (defmethod epsilon ((x cl
:float
))
1625 (short-float short-float-epsilon
)
1626 (single-float single-float-epsilon
)
1627 (double-float double-float-epsilon
)
1628 (long-float long-float-epsilon
)))
1630 (defmethod epsilon ((x cl
:complex
))
1631 (epsilon (cl:realpart x
)))
1633 (defmethod epsilon ((x bigfloat
))
1634 ;; epsilon is just above 2^(-fpprec).
1635 (make-instance 'bigfloat
1636 :real
(maxima::bcons
(list (1+ (ash 1 (1- maxima
::fpprec
)))
1637 (- (1- maxima
::fpprec
))))))
1639 (defmethod epsilon ((x complex-bigfloat
))
1640 (epsilon (realpart x
)))
1644 ;; Compiler macros to convert + to multiple calls to two-arg-+. Same
1646 (define-compiler-macro + (&whole form
&rest args
)
1647 (declare (ignore form
))
1650 (do ((args (cdr args
) (cdr args
))
1652 `(two-arg-+ ,res
,(car args
))))
1653 ((null args
) res
))))
1655 (define-compiler-macro -
(&whole form number
&rest more-numbers
)
1656 (declare (ignore form
))
1658 (do ((nlist more-numbers
(cdr nlist
))
1660 ((atom nlist
) result
)
1661 (declare (list nlist
))
1662 (setq result
`(two-arg-- ,result
,(car nlist
))))
1663 `(unary-minus ,number
)))
1665 (define-compiler-macro * (&whole form
&rest args
)
1666 (declare (ignore form
))
1669 (do ((args (cdr args
) (cdr args
))
1671 `(two-arg-* ,res
,(car args
))))
1672 ((null args
) res
))))
1674 (define-compiler-macro / (number &rest more-numbers
)
1676 (do ((nlist more-numbers
(cdr nlist
))
1678 ((atom nlist
) result
)
1679 (declare (list nlist
))
1680 (setq result
`(two-arg-/ ,result
,(car nlist
))))
1681 `(unary-divide ,number
)))
1683 (define-compiler-macro /= (&whole form number
&rest more-numbers
)
1684 ;; Convert (/= x y) to (not (two-arg-= x y)). Should we try to
1685 ;; handle a few more cases?
1686 (if (cdr more-numbers
)
1688 `(not (two-arg-= ,number
,(car more-numbers
)))))
1690 ;; Compiler macros to convert <, >, <=, and >= into multiple calls of
1691 ;; the corresponding two-arg-<foo> function.
1694 (let ((method (intern (concatenate 'string
1695 (string '#:two-arg-
)
1696 (symbol-name op
)))))
1697 `(define-compiler-macro ,op
(number &rest more-numbers
)
1698 (do* ((n number
(car nlist
))
1699 (nlist more-numbers
(cdr nlist
))
1702 `(and ,@(nreverse res
)))
1703 (push `(,',method
,n
,(car nlist
)) res
))))))
1709 (defmethod integer-decode-float ((x cl
:float
))
1710 (cl:integer-decode-float x
))
1712 (defmethod integer-decode-float ((x bigfloat
))
1713 (let ((r (real-value x
)))
1714 (values (abs (second r
))
1715 (- (third r
) (third (first r
)))
1716 (signum (second r
)))))
1718 (defmethod decode-float ((x cl
:float
))
1719 (cl:decode-float x
))
1721 (defmethod decode-float ((x bigfloat
))
1722 (let ((r (real-value x
)))
1723 (values (make-instance 'bigfloat
1724 :real
(maxima::bcons
(list (abs (second r
)) 0)))
1726 (bigfloat (signum (second r
))))))
1729 (defmethod float ((x real
) (y cl
:float
))
1732 (defmethod float ((x real
) (y bigfloat
))
1736 ;; Like Maxima's fp2flo, but for single-float numbers.
1737 (defun fp2single (l)
1738 (let ((precision (caddar l
))
1740 (exponent (caddr l
))
1741 (fpprec (float-digits 1f0
))
1743 ;; Round the mantissa to the number of bits of precision of the
1744 ;; machine, and then convert it to a floating point fraction. We
1745 ;; have 0.5 <= mantissa < 1
1746 (setq mantissa
(maxima::quotient
(maxima::fpround mantissa
)
1748 ;; Multiply the mantissa by the exponent portion. I'm not sure
1749 ;; why the exponent computation is so complicated.
1751 ;; GCL doesn't signal overflow from scale-float if the number
1752 ;; would overflow. We have to do it this way. 0.5 <= mantissa <
1753 ;; 1. The largest double-float is .999999 * 2^128. So if the
1754 ;; exponent is 128 or higher, we have an overflow.
1755 (let ((e (+ exponent
(- precision
) maxima
::*m fpprec
)))
1756 (if (>= (abs e
) 129)
1757 (maxima::merror
(intl:gettext
"FP2SINGLE: floating point overflow converting ~:M to float.") l
)
1758 (cl:scale-float mantissa e
)))))
1761 (defmethod float ((x bigfloat
) (y cl
:float
))
1762 (if (typep y
'maxima
::flonum
)
1763 (maxima::fp2flo
(real-value x
))
1764 (fp2single (real-value x
))))
1766 (defmethod random ((x cl
:float
) &optional
(state cl
:*random-state
*))
1767 (cl:random x state
))
1768 (defmethod random ((x integer
) &optional
(state cl
:*random-state
*))
1769 (cl:random x state
))
1771 (defmethod random ((x bigfloat
) &optional
(state cl
:*random-state
*))
1772 ;; Generate an integer with fpprec bits, and convert to a bigfloat
1773 ;; by making the exponent 0. Then multiply by the arg to get the
1776 (let ((int (cl:random
(ash 1 maxima
::fpprec
) state
)))
1777 (* x
(bigfloat (maxima::bcons
(list int
0)))))
1778 (error "Argument is not a positive bigfloat: ~A~%" x
)))
1780 (defmethod signum ((x number
))
1783 (defmethod signum ((x bigfloat
))
1791 (defmethod signum ((x complex-bigfloat
))
1794 (defmethod float-sign ((x cl
:float
))
1797 (defmethod float-sign ((x bigfloat
))
1802 (defmethod float-digits ((x cl
:float
))
1803 (cl:float-digits x
))
1805 (defmethod float-digits ((x bigfloat
))
1806 ;; Should we just return fpprec or should we get the actual number
1807 ;; of bits in the bigfloat number? We choose the latter in case the
1808 ;; number and fpprec don't match.
1809 (let ((r (slot-value x
'real
)))
1812 (defmethod rational ((x real
))
1815 (defmethod rational ((x bigfloat
))
1816 (destructuring-bind ((marker simp prec
) mantissa exp
)
1818 (declare (ignore marker simp
))
1819 (* mantissa
(expt 2 (- exp prec
)))))
1821 (defmethod rationalize ((x real
))
1824 ;;; This routine taken from CMUCL, which, in turn is a routine from
1825 ;;; CLISP, which is GPL.
1827 ;;; I (rtoy) have modified it from CMUCL so that it only handles bigfloats.
1829 ;;; RATIONALIZE -- Public
1831 ;;; The algorithm here is the method described in CLISP. Bruno Haible has
1832 ;;; graciously given permission to use this algorithm. He says, "You can use
1833 ;;; it, if you present the following explanation of the algorithm."
1835 ;;; Algorithm (recursively presented):
1836 ;;; If x is a rational number, return x.
1837 ;;; If x = 0.0, return 0.
1838 ;;; If x < 0.0, return (- (rationalize (- x))).
1840 ;;; Call (integer-decode-float x). It returns a m,e,s=1 (mantissa,
1841 ;;; exponent, sign).
1842 ;;; If m = 0 or e >= 0: return x = m*2^e.
1843 ;;; Search a rational number between a = (m-1/2)*2^e and b = (m+1/2)*2^e
1844 ;;; with smallest possible numerator and denominator.
1845 ;;; Note 1: If m is a power of 2, we ought to take a = (m-1/4)*2^e.
1846 ;;; But in this case the result will be x itself anyway, regardless of
1847 ;;; the choice of a. Therefore we can simply ignore this case.
1848 ;;; Note 2: At first, we need to consider the closed interval [a,b].
1849 ;;; but since a and b have the denominator 2^(|e|+1) whereas x itself
1850 ;;; has a denominator <= 2^|e|, we can restrict the search to the open
1852 ;;; So, for given a and b (0 < a < b) we are searching a rational number
1853 ;;; y with a <= y <= b.
1854 ;;; Recursive algorithm fraction_between(a,b):
1855 ;;; c := (ceiling a)
1857 ;;; then return c ; because a <= c < b, c integer
1859 ;;; ; a is not integer (otherwise we would have had c = a < b)
1860 ;;; k := c-1 ; k = floor(a), k < a < b <= k+1
1861 ;;; return y = k + 1/fraction_between(1/(b-k), 1/(a-k))
1862 ;;; ; note 1 <= 1/(b-k) < 1/(a-k)
1864 ;;; You can see that we are actually computing a continued fraction expansion.
1866 ;;; Algorithm (iterative):
1867 ;;; If x is rational, return x.
1868 ;;; Call (integer-decode-float x). It returns a m,e,s (mantissa,
1869 ;;; exponent, sign).
1870 ;;; If m = 0 or e >= 0, return m*2^e*s. (This includes the case x = 0.0.)
1871 ;;; Create rational numbers a := (2*m-1)*2^(e-1) and b := (2*m+1)*2^(e-1)
1872 ;;; (positive and already in lowest terms because the denominator is a
1873 ;;; power of two and the numerator is odd).
1874 ;;; Start a continued fraction expansion
1875 ;;; p[-1] := 0, p[0] := 1, q[-1] := 1, q[0] := 0, i := 0.
1877 ;;; c := (ceiling a)
1879 ;;; then k := c-1, partial_quotient(k), (a,b) := (1/(b-k),1/(a-k)),
1881 ;;; finally partial_quotient(c).
1882 ;;; Here partial_quotient(c) denotes the iteration
1883 ;;; i := i+1, p[i] := c*p[i-1]+p[i-2], q[i] := c*q[i-1]+q[i-2].
1884 ;;; At the end, return s * (p[i]/q[i]).
1885 ;;; This rational number is already in lowest terms because
1886 ;;; p[i]*q[i-1]-p[i-1]*q[i] = (-1)^i.
1888 (defmethod rationalize ((x bigfloat
))
1889 (multiple-value-bind (frac expo sign
)
1890 (integer-decode-float x
)
1891 (cond ((or (zerop frac
) (>= expo
0))
1896 ;; expo < 0 and (2*m-1) and (2*m+1) are coprime to 2^(1-e),
1897 ;; so build the fraction up immediately, without having to do
1899 (let ((a (/ (- (* 2 frac
) 1) (ash 1 (- 1 expo
))))
1900 (b (/ (+ (* 2 frac
) 1) (ash 1 (- 1 expo
))))
1905 (do ((c (ceiling a
) (ceiling a
)))
1907 (let ((top (+ (* c p1
) p0
))
1908 (bot (+ (* c q1
) q0
)))
1909 (/ (if (minusp sign
)
1914 (p2 (+ (* k p1
) p0
))
1915 (q2 (+ (* k q1
) q0
)))
1916 (psetf a
(/ (- b k
))
1923 (defun coerce (obj type
)
1924 (flet ((coerce-error ()
1925 (error "Cannot coerce ~A to type ~S" obj type
)))
1926 (cond ((typep obj type
)
1928 ((subtypep type
'bigfloat
)
1929 ;; (coerce foo 'bigfloat). Foo has to be a real
1930 (cond ((typep obj
'real
)
1934 ((subtypep type
'complex-bigfloat
)
1935 ;; (coerce foo 'complex-bigfloat). Foo has to be a real or complex
1936 (cond ((typep obj
'real
)
1938 ((typep obj
'cl
:complex
)
1940 ((typep obj
'bigfloat
)
1944 ((typep obj
'bigfloat
)
1945 ;; (coerce bigfloat foo)
1946 (cond ((subtypep type
'cl
:float
)
1947 (float obj
(cl:coerce
0 type
)))
1948 ((subtypep type
'(cl:complex long-float
))
1949 (cl:complex
(float (realpart obj
) 1l0)
1950 (float (imagpart obj
) 1l0)))
1951 ((subtypep type
'(cl:complex double-float
))
1952 (cl:complex
(float (realpart obj
) 1d0
)
1953 (float (imagpart obj
) 1d0
)))
1954 ((subtypep type
'(cl:complex single-float
))
1955 (cl:complex
(float (realpart obj
) 1f0
)
1956 (float (imagpart obj
) 1f0
)))
1957 ((subtypep type
'cl
:complex
)
1958 ;; What should we do here? Return a
1959 ;; complex-bigfloat? A complex double-float?
1960 ;; complex single-float? I arbitrarily select
1961 ;; complex maxima:flonum for now.
1962 (cl:complex
(float (realpart obj
) 1.0)
1963 (float (imagpart obj
) 1.0)))
1966 ((typep obj
'complex-bigfloat
)
1967 ;; (coerce complex-bigfloat foo)
1968 (cond ((subtypep type
'complex-bigfloat
)
1970 ((subtypep type
'(cl:complex long-float
))
1971 (cl:complex
(float (realpart obj
) 1l0)
1972 (float (imagpart obj
) 1l0)))
1973 ((subtypep type
'(cl:complex double-float
))
1974 (cl:complex
(float (realpart obj
) 1d0
)
1975 (float (imagpart obj
) 1d0
)))
1976 ((subtypep type
'(cl:complex single-float
))
1977 (cl:complex
(float (realpart obj
) 1f0
)
1978 (float (imagpart obj
) 1f0
)))
1982 (cl:coerce obj type
)))))
1986 ;;; Return a value of pi with the same precision as the argument.
1987 ;;; For rationals, we return a single-float approximation.
1988 (defmethod %pi
((x cl
:rational
))
1989 (cl:coerce cl
:pi
'single-float
))
1991 (defmethod %pi
((x cl
:float
))
1994 (defmethod %pi
((x bigfloat
))
1995 (to (maxima::bcons
(maxima::fppi
))))
1997 (defmethod %pi
((x cl
:complex
))
1998 (cl:float cl
:pi
(realpart x
)))
2000 (defmethod %pi
((x complex-bigfloat
))
2001 (to (maxima::bcons
(maxima::fppi
))))
2005 ;;; Return a value of e with the same precision as the argument.
2006 ;;; For rationals, we return a single-float approximation.
2007 (defmethod %e
((x cl
:rational
))
2008 (cl:coerce maxima
::%e-val
'single-float
))
2010 (defmethod %e
((x cl
:float
))
2011 (cl:float maxima
::%e-val x
))
2013 (defmethod %e
((x bigfloat
))
2014 (to (maxima::bcons
(maxima::fpe
))))
2016 (defmethod %e
((x cl
:complex
))
2017 (cl:float maxima
::%e-val
(realpart x
)))
2019 (defmethod %e
((x complex-bigfloat
))
2020 (to (maxima::bcons
(maxima::fpe
))))
2022 ;;;; Useful routines
2024 ;;; Evaluation of continued fractions
2026 (defvar *debug-cf-eval
*
2028 "When true, enable some debugging prints when evaluating a
2029 continued fraction.")
2031 ;; Max number of iterations allowed when evaluating the continued
2032 ;; fraction. When this is reached, we assume that the continued
2033 ;; fraction did not converge.
2034 (defvar *max-cf-iterations
*
2036 "Max number of iterations allowed when evaluating the continued
2037 fraction. When this is reached, we assume that the continued
2038 fraction did not converge.")
2040 ;;; LENTZ - External
2042 ;;; Lentz's algorithm for evaluating continued fractions.
2044 ;;; Let the continued fraction be:
2047 ;;; b0 + ---- ---- ----
2051 ;;; Then LENTZ expects two functions, each taking a single fixnum
2052 ;;; index. The first returns the b term and the second returns the a
2053 ;;; terms as above for a give n.
2054 (defun lentz (bf af
)
2055 (let ((tiny-value-count 0))
2056 (flet ((value-or-tiny (v)
2057 ;; If v is zero, return a "tiny" number.
2060 (incf tiny-value-count
)
2062 ((or double-float cl
:complex
)
2063 (sqrt least-positive-normalized-double-float
))
2064 ((or bigfloat complex-bigfloat
)
2065 ;; What is a "tiny" bigfloat? Bigfloats have
2066 ;; unbounded exponents, so we need something
2067 ;; small, but not zero. Arbitrarily choose an
2068 ;; exponent of 50 times the precision.
2069 (expt 10 (- (* 50 maxima
::$fpprec
))))))
2071 (let* ((f (value-or-tiny (funcall bf
0)))
2076 for j from
1 upto
*max-cf-iterations
*
2077 for an
= (funcall af j
)
2078 for bn
= (funcall bf j
)
2080 (setf d
(value-or-tiny (+ bn
(* an d
))))
2081 (setf c
(value-or-tiny (+ bn
(/ an c
))))
2082 (when *debug-cf-eval
*
2083 (format t
"~&j = ~d~%" j
)
2084 (format t
" an = ~s~%" an
)
2085 (format t
" bn = ~s~%" bn
)
2086 (format t
" c = ~s~%" c
)
2087 (format t
" d = ~s~%" d
))
2088 (let ((delta (/ c d
)))
2090 (setf f
(* f delta
))
2091 (when *debug-cf-eval
*
2092 (format t
" dl= ~S (|dl - 1| = ~S)~%" delta
(abs (1- delta
)))
2093 (format t
" f = ~S~%" f
))
2094 (when (<= (abs (- delta
1)) eps
)
2095 (return-from lentz
(values f j tiny-value-count
)))))
2097 (error 'simple-error
2098 :format-control
"~<Continued fraction failed to converge after ~D iterations.~% Delta = ~S~>"
2099 :format-arguments
(list *max-cf-iterations
* (/ c d
))))))))
2101 ;;; SUM-POWER-SERIES - External
2103 ;;; SUM-POWER-SERIES sums the given power series, adding terms until
2104 ;;; the next term would not change the sum.
2106 ;;; The series to be summed is
2108 ;;; S = 1 + sum(c[k]*x^k, k, 1, inf)
2109 ;;; = 1 + sum(prod(f[n]*x, n, 1, k), k, 1, inf)
2111 ;;; where f[n] = c[n]/c[n-1].
2113 (defun sum-power-series (x f
)
2114 (let ((eps (epsilon x
)))
2116 (sum 1 (+ sum term
))
2117 (term (* x
(funcall f
1))
2118 (* term x
(funcall f k
))))
2119 ((< (abs term
) (* eps
(abs sum
)))
2122 (format t
"~4d: ~S ~S ~S~%" k sum term
(funcall f k
)))))
2124 ;; Format bigfloats using ~E format. This is suitable as a ~// format.
2126 ;; NOTE: This is a modified version of FORMAT-EXPONENTIAL from CMUCL to
2127 ;; support printing of bfloats.
2129 (defun format-e (stream number colonp atp
2131 overflowchar padchar exponentchar
)
2134 (maxima::bfloat-format-e stream
(real-value number
) colonp atp
2137 (or padchar
#\space
)
2138 (or exponentchar
#\b)))
2140 ;; FIXME: Do something better than this since this doesn't honor
2141 ;; any of the parameters.
2142 (princ number stream
))
2144 ;; We were given some other kind of object. Just use CL's normal
2145 ;; ~E printer to print it.
2147 (with-output-to-string (s)
2148 ;; Construct a suitable ~E format string from the given
2149 ;; parameters. First, handle w,d,e,k.
2150 (write-string "~V,V,V,V," s
)
2152 (format s
"'~C," overflowchar
)
2153 (write-string "," s
))
2155 (format s
"'~C," padchar
)
2156 (write-string "," s
))
2158 (format s
"'~C" exponentchar
))
2163 (write-char #\E s
))))
2164 (format stream f w d e k number
)))))
2167 (defmacro assert-equal
(expected form
)
2168 (let ((result (gensym))
2170 `(let ((,e
,expected
)
2172 (unless (equal ,e
,result
)
2173 (format *debug-io
* "Assertion failed: Expected ~S but got ~S~%" ,e
,result
)))))
2175 (assert-equal " 0.990E+00" (format nil
2176 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2177 (bigfloat:bigfloat
99/100)))
2178 (assert-equal " 0.999E+00" (format nil
2179 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2180 (bigfloat:bigfloat
999/1000)))
2181 ;; Actually " 0.100E+01", but format-e doesn't round the output.
2182 (assert-equal " 0.999E+00" (format nil
2183 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2184 (bigfloat:bigfloat
9999/10000)))
2185 (assert-equal " 0.999E-04" (format nil
2186 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2187 (bigfloat:bigfloat
0000999/10000000)))
2188 ;; Actually " 0.100E-03", but format-e doesn't round the output.
2189 (assert-equal " 0.999E-0e" (format nil
2190 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2191 (bigfloat:bigfloat
00009999/100000000)))
2192 (assert-equal " 9.999E-05" (format nil
2193 "~11,3,2,,'*,,'E/bigfloat::format-e/"
2194 (bigfloat:bigfloat
00009999/100000000)))
2195 ;; Actually " 1.000E-04", but format-e doesn't round the output.
2196 (assert-equal " 9.999E-05" (format nil
2197 "~11,3,2,,'*,,'E/bigfloat::format-e/"
2198 (bigfloat:bigfloat
000099999/1000000000)))
2199 ;; All of these currently fail.
2200 (assert-equal ".00123d+6" (format nil
2201 "~9,,,-2/bigfloat::format-e/"
2202 (bigfloat:bigfloat
1.2345689d3
)))
2203 (assert-equal "-.0012d+6" (format nil
2204 "~9,,,-2/bigfloat::format-e/"
2205 (bigfloat:bigfloat -
1.2345689d3
)))
2206 (assert-equal ".00123d+0" (format nil
2207 "~9,,,-2/bigfloat::format-e/"
2208 (bigfloat:bigfloat
1.2345689d-3
)))
2209 (assert-equal "-.0012d+0" (format nil
2210 "~9,,,-2/bigfloat::format-e/"
2211 (bigfloat:bigfloat -
1.2345689d-3
)))
2213 ;; These fail because too many digits are printed and because the
2214 ;; scale factor isn't properly applied.
2215 (assert-equal ".00000003d+8" (format nil
2217 (bigfloat:bigfloat pi
)))
2218 (assert-equal ".000003d+6" (format nil
2220 (bigfloat:bigfloat pi
)))
2221 (assert-equal "3141600.d-6" (format nil
2223 (bigfloat:bigfloat pi
)))
2224 (assert-equal " 314.16d-2" (format nil
2226 (bigfloat:bigfloat pi
)))
2227 (assert-equal " 31416.d-4" (format nil
2229 (bigfloat:bigfloat pi
)))
2230 (assert-equal " 0.3142d+1" (format nil
2232 (bigfloat:bigfloat pi
)))
2233 (assert-equal ".03142d+2" (format nil
2235 (bigfloat:bigfloat pi
)))
2236 (assert-equal "0.003141592653589793d+3" (format nil
2238 (bigfloat:bigfloat pi
)))
2239 (assert-equal "31.41592653589793d-1" (format nil
2241 (bigfloat:bigfloat pi
)))
2242 ;; Fails because exponent is printed as "b0" instead of "b+0"
2243 (assert-equal "3.141592653589793b+0" (format nil
"~E" (bigfloat:bigfloat pi
)))
2246 ;; These fail because too many digits are printed and because the
2247 ;; scale factor isn't properly applied.
2248 (assert-equal ".03142d+2" (format nil
"~9,5,,-1E" (bigfloat:bigfloat pi
)))
2249 (assert-equal " 0.03142d+2" (format nil
"~11,5,,-1E" (bigfloat:bigfloat pi
)))
2250 (assert-equal "| 3141593.d-06|" (format nil
"|~13,6,2,7E|" (bigfloat:bigfloat pi
)))
2251 (assert-equal "0.314d+01" (format nil
"~9,3,2,0,'%E" (bigfloat:bigfloat pi
)))
2252 (assert-equal "+.003d+03" (format nil
"~9,3,2,-2,'%@E" (bigfloat:bigfloat pi
)))
2253 (assert-equal "+0.003d+03" (format nil
"~10,3,2,-2,'%@E" (bigfloat:bigfloat pi
)))
2254 (assert-equal "=====+0.003d+03" (format nil
"~15,3,2,-2,'%,'=@E" (bigfloat:bigfloat pi
)))
2255 (assert-equal "0.003d+03" (format nil
"~9,3,2,-2,'%E" (bigfloat:bigfloat pi
)))
2256 (assert-equal "%%%%%%%%" (format nil
"~8,3,2,-2,'%@E" (bigfloat:bigfloat pi
)))
2259 (assert-equal "0.0f+0" (format nil
"~e" 0))
2261 ;; Fails because exponent is printed as "b0" instead of "b+0'
2262 (assert-equal "0.0b+0" (format nil
"~e" (bigfloat:bigfloat
0d0
)))
2263 ;; Fails because exponent is printed as "b0 " instead of "b+0000"
2264 (assert-equal "0.0b+0000" (format nil
"~9,,4e" (bigfloat:bigfloat
0d0
)))
2265 ;; Fails because exponent is printed as "b4" isntead of "b+4"
2266 (assert-equal "1.2345678901234567b+4" (format nil
"~E"
2267 (bigfloat:bigfloat
1.234567890123456789d4
)))
2269 ;; Fails because exponent is printed as "b36" instead of "b+36"
2270 (assert-equal "1.32922799578492b+36" (format nil
"~20E"
2271 (bigfloat:bigfloat
(expt 2d0
120))))
2272 ;; Fails because too many digits are printed and the exponent doesn't include "+".
2273 (assert-equal " 1.32922800b+36" (format nil
"~21,8E"
2274 (bigfloat:bigfloat
(expt 2d0
120))))
2278 ;; Format bigfloats using ~F format. This is suitable as a ~// format.
2280 ;; NOTE: This is a modified version of FORMAT-FIXED from CMUCL to
2281 ;; support printing of bfloats.
2283 (defun format-f (stream number colonp atp
2284 &optional w d k overflowchar padchar
)
2287 (maxima::bfloat-format-f stream
(real-value number
) colonp atp
2290 (or padchar
#\space
)))
2292 ;; FIXME: Do something better than this since this doesn't honor
2293 ;; any of the parameters.
2294 (princ number stream
))
2296 ;; We were given some other kind of object. Just use CL's normal
2297 ;; ~F printer to print it.
2299 (with-output-to-string (s)
2300 ;; Construct a suitable ~F format string from the given
2301 ;; parameters. First handle w,d,k.
2302 (write-string "~V,V,V," s
)
2304 (format s
"'~C," overflowchar
)
2305 (write-string "," s
))
2306 (if (char= padchar
#\space
)
2307 (write-string "," s
)
2308 (format s
"'~C," padchar
))
2313 (write-char #\F s
))))
2314 (format stream f w d k number
)))))
2316 ;; Format bigfloats using ~G format. This is suitable as a ~// format.
2318 ;; NOTE: This is a modified version of FORMAT-GENERAL from CMUCL to
2319 ;; support printing of bfloats.
2321 (defun format-g (stream number colonp atp
2322 &optional w d e k overflowchar padchar marker
)
2325 (maxima::bfloat-format-g stream
(real-value number
) colonp atp
2328 (or padchar
#\space
)
2331 ;; FIXME: Do something better than this since this doesn't honor
2332 ;; any of the parameters.
2333 (princ number stream
))
2335 ;; We were given some other kind of object. Just use CL's normal
2336 ;; ~G printer to print it.
2338 (with-output-to-string (s)
2339 ;; Construct a suitable ~E format string from the given
2340 ;; parameters. First, handle w,d,e,k.
2341 (write-string "~V,V,V,V," s
)
2343 (format s
"'~C," overflowchar
)
2344 (write-string "," s
))
2346 (format s
"'~C," padchar
)
2347 (write-string "," s
))
2349 (format s
"'~C" marker
))
2354 (write-char #\G s
))))
2355 (format stream f w d e k number
)))))