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 #-gcl
#:bigfloat
#+gcl
"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 ;; GCL doesn't have the REAL class! But since a real is a rational or
229 ;; float, we can fake it by defining methods on rationals and floats
232 (defmethod realp ((x cl
:real
))
237 (defmethod realp ((x cl
:rational
))
239 (defmethod realp ((x cl
:float
))
244 (defmethod realp ((x bigfloat
))
247 (defmethod realp ((x t
))
251 (defmethod complexp ((x cl
:complex
))
254 (defmethod complexp ((x complex-bigfloat
))
257 (defmethod complexp ((x t
))
261 (defmethod numberp ((x cl
:number
))
264 (defmethod numberp ((x bigfloat
))
267 (defmethod numberp ((x complex-bigfloat
))
270 (defmethod numberp ((x t
))
273 (defmethod make-load-form ((x complex-bigfloat
) &optional environment
)
274 (declare (ignore environment
))
275 `(make-instance ',(class-of x
)
276 :real
',(real-value x
)
277 :imag
',(imag-value x
)))
279 ;; The print-object and describe-object methods are mostly for
280 ;; debugging purposes. Maxima itself shouldn't ever see such objects.
281 (defmethod print-object ((x bigfloat
) stream
)
282 (let ((r (cdr (real-value x
))))
283 (multiple-value-bind (sign output-list
)
284 (if (cl:minusp
(first r
))
285 (values "-" (maxima::fpformat
(maxima::bcons
(list (cl:-
(first r
)) (second r
)))))
286 (values "+" (maxima::fpformat
(maxima::bcons r
))))
287 (format stream
"~A~{~D~}" sign output-list
))))
289 (defmethod print-object ((x complex-bigfloat
) stream
)
290 (format stream
"~A~A*%i" (realpart x
) (imagpart x
)))
292 (defmethod describe-object ((x bigfloat
) stream
)
293 (let ((r (slot-value x
'real
)))
294 (format stream
"~&~S is a ~D-bit BIGFLOAT with mantissa ~D and exponent ~D~%"
295 x
(third (first r
)) (second r
) (third r
))))
297 (defmethod describe-object ((x complex-bigfloat
) stream
)
298 (format stream
"~S is a COMPLEX-BIGFLOAT~%" x
)
299 (describe-object (make-instance 'bigfloat
:real
(slot-value x
'real
)) stream
)
300 (describe-object (make-instance 'bigfloat
:real
(slot-value x
'imag
)) stream
))
304 (:documentation
"Add 1"))
307 (:documentation
"Subtract 1"))
310 (defgeneric two-arg-
+ (a b
)
311 (:documentation
"A + B"))
313 (defgeneric two-arg--
(a b
)
314 (:documentation
"A - B"))
316 (defgeneric two-arg-
* (a b
)
317 (:documentation
"A * B"))
319 (defgeneric two-arg-
/ (a b
)
320 (:documentation
"A / B"))
322 (defgeneric two-arg-
< (a b
)
323 (:documentation
"A < B"))
325 (defgeneric two-arg-
> (a b
)
326 (:documentation
"A > B"))
328 (defgeneric two-arg-
<= (a b
)
329 (:documentation
"A <= B"))
331 (defgeneric two-arg-
>= (a b
)
332 (:documentation
"A >= B"))
334 (defgeneric two-arg-
= (a b
)
335 (:documentation
"A = B?"))
338 (defgeneric unary-minus
(a)
339 (:documentation
"-A"))
341 (defgeneric unary-divide
(a)
342 (:documentation
"1 / A"))
345 ;;; Basic arithmetic operations
349 (defmethod add1 ((a number
))
352 (defmethod add1 ((a bigfloat
))
353 (make-instance 'bigfloat
355 (maxima::fpplus
(cdr (real-value a
))
358 (defmethod add1 ((a complex-bigfloat
))
359 (make-instance 'complex-bigfloat
361 (maxima::fpplus
(cdr (real-value a
))
363 :imag
(imag-value a
)))
365 (defmethod sub1 ((a number
))
368 (defmethod sub1 ((a bigfloat
))
369 (make-instance 'bigfloat
371 (maxima::fpdifference
(cdr (real-value a
))
374 (defmethod sub1 ((a complex-bigfloat
))
375 (make-instance 'complex-bigfloat
377 (maxima::fpdifference
(cdr (real-value a
))
379 :imag
(imag-value a
)))
381 (declaim (inline 1+ 1-
))
390 (defmethod two-arg-+ ((a cl
:number
) (b cl
:number
))
393 (defmethod two-arg-+ ((a bigfloat
) (b bigfloat
))
394 (make-instance 'bigfloat
396 (maxima::fpplus
(cdr (real-value a
))
397 (cdr (real-value b
))))))
399 (defmethod two-arg-+ ((a complex-bigfloat
) (b complex-bigfloat
))
400 (make-instance 'complex-bigfloat
402 (maxima::fpplus
(cdr (real-value a
))
403 (cdr (real-value b
))))
405 (maxima::fpplus
(cdr (imag-value a
))
406 (cdr (imag-value b
))))))
408 ;; Handle contagion for two-arg-+
409 (defmethod two-arg-+ ((a bigfloat
) (b cl
:float
))
410 (make-instance 'bigfloat
412 (maxima::fpplus
(cdr (real-value a
))
415 (defmethod two-arg-+ ((a bigfloat
) (b cl
:rational
))
416 (make-instance 'bigfloat
418 (maxima::fpplus
(cdr (real-value a
))
421 (defmethod two-arg-+ ((a bigfloat
) (b cl
:complex
))
422 (make-instance 'complex-bigfloat
424 (maxima::fpplus
(cdr (real-value a
))
425 (cdr (intofp (realpart b
)))))
426 :imag
(intofp (imagpart b
))))
428 (defmethod two-arg-+ ((a cl
:number
) (b bigfloat
))
431 (defmethod two-arg-+ ((a complex-bigfloat
) (b bigfloat
))
432 (make-instance 'complex-bigfloat
434 (maxima::fpplus
(cdr (real-value a
))
435 (cdr (real-value b
))))
436 :imag
(imag-value a
)))
438 (defmethod two-arg-+ ((a complex-bigfloat
) (b number
))
439 (make-instance 'complex-bigfloat
441 (maxima::fpplus
(cdr (real-value a
))
442 (cdr (intofp (cl:realpart b
)))))
444 (maxima::fpplus
(cdr (imag-value a
))
445 (cdr (intofp (cl:imagpart b
)))))))
447 (defmethod two-arg-+ ((a bigfloat
) (b complex-bigfloat
))
450 (defmethod two-arg-+ ((a number
) (b complex-bigfloat
))
453 (defun + (&rest args
)
456 (do ((args (cdr args
) (cdr args
))
458 (two-arg-+ res
(car args
))))
462 (defmethod unary-minus ((a number
))
465 (defmethod unary-minus ((a bigfloat
))
466 (make-instance 'bigfloat
468 (maxima::fpminus
(cdr (real-value a
))))))
470 (defmethod unary-minus ((a complex-bigfloat
))
471 (make-instance 'complex-bigfloat
473 (maxima::fpminus
(cdr (real-value a
))))
475 (maxima::fpminus
(cdr (imag-value a
))))))
477 ;;; Subtract two numbers
478 (defmethod two-arg-- ((a number
) (b number
))
481 (defmethod two-arg-- ((a bigfloat
) (b bigfloat
))
482 (make-instance 'bigfloat
484 (maxima::fpdifference
(cdr (real-value a
))
485 (cdr (real-value b
))))))
487 (defmethod two-arg-- ((a complex-bigfloat
) (b complex-bigfloat
))
488 (make-instance 'complex-bigfloat
490 (maxima::fpdifference
(cdr (real-value a
))
491 (cdr (real-value b
))))
493 (maxima::fpdifference
(cdr (imag-value a
))
494 (cdr (imag-value b
))))))
496 ;; Handle contagion for two-arg--
497 (defmethod two-arg-- ((a bigfloat
) (b cl
:float
))
498 (make-instance 'bigfloat
500 (maxima::fpdifference
(cdr (real-value a
))
503 (defmethod two-arg-- ((a bigfloat
) (b cl
:rational
))
504 (make-instance 'bigfloat
506 (maxima::fpdifference
(cdr (real-value a
))
509 (defmethod two-arg-- ((a bigfloat
) (b cl
:complex
))
510 (make-instance 'complex-bigfloat
512 (maxima::fpdifference
(cdr (real-value a
))
513 (cdr (intofp (realpart b
)))))
514 :imag
(maxima::bcons
(maxima::fpminus
(cdr (intofp (imagpart b
)))))))
516 (defmethod two-arg-- ((a cl
:float
) (b bigfloat
))
517 (make-instance 'bigfloat
519 (maxima::fpdifference
(cdr (intofp a
))
520 (cdr (real-value b
))))))
522 (defmethod two-arg-- ((a cl
:rational
) (b bigfloat
))
523 (make-instance 'bigfloat
525 (maxima::fpdifference
(cdr (intofp a
))
526 (cdr (real-value b
))))))
528 (defmethod two-arg-- ((a cl
:complex
) (b bigfloat
))
529 (two-arg-- (bigfloat (cl:realpart a
) (cl:imagpart a
)) b
))
531 (defmethod two-arg-- ((a complex-bigfloat
) (b bigfloat
))
532 (make-instance 'complex-bigfloat
534 (maxima::fpdifference
(cdr (real-value a
))
535 (cdr (real-value b
))))
536 :imag
(imag-value a
)))
538 (defmethod two-arg-- ((a complex-bigfloat
) (b number
))
540 (two-arg-- a
(bigfloat (cl:realpart b
) (cl:imagpart b
)))
541 (two-arg-- a
(bigfloat b
))))
543 (defmethod two-arg-- ((a bigfloat
) (b complex-bigfloat
))
544 (make-instance 'complex-bigfloat
546 (maxima::fpdifference
(cdr (real-value a
))
547 (cdr (real-value b
))))
548 :imag
(maxima::bcons
(maxima::fpminus
(cdr (imag-value b
))))))
550 (defmethod two-arg-- ((a number
) (b complex-bigfloat
))
552 (two-arg-- (bigfloat (cl:realpart a
) (cl:imagpart a
))
554 (two-arg-- (bigfloat a
) b
)))
556 (defun - (number &rest more-numbers
)
558 (do ((nlist more-numbers
(cdr nlist
))
560 ((atom nlist
) result
)
561 (declare (list nlist
))
562 (setq result
(two-arg-- result
(car nlist
))))
563 (unary-minus number
)))
565 ;;; Multiply two numbers
566 (defmethod two-arg-* ((a number
) (b number
))
569 (defmethod two-arg-* ((a bigfloat
) (b bigfloat
))
570 (make-instance 'bigfloat
572 (maxima::fptimes
* (cdr (real-value a
))
573 (cdr (real-value b
))))))
575 (defmethod two-arg-* ((a complex-bigfloat
) (b complex-bigfloat
))
576 (let ((a-re (cdr (real-value a
)))
577 (a-im (cdr (imag-value a
)))
578 (b-re (cdr (real-value b
)))
579 (b-im (cdr (imag-value b
))))
580 (make-instance 'complex-bigfloat
582 (maxima::fpdifference
(maxima::fptimes
* a-re b-re
)
583 (maxima::fptimes
* a-im b-im
)))
585 (maxima::fpplus
(maxima::fptimes
* a-re b-im
)
586 (maxima::fptimes
* a-im b-re
))))))
588 ;; Handle contagion for two-arg-*
589 (defmethod two-arg-* ((a bigfloat
) (b cl
:float
))
590 (make-instance 'bigfloat
592 (maxima::fptimes
* (cdr (real-value a
))
595 (defmethod two-arg-* ((a bigfloat
) (b cl
:rational
))
596 (make-instance 'bigfloat
598 (maxima::fptimes
* (cdr (real-value a
))
601 (defmethod two-arg-* ((a bigfloat
) (b cl
:complex
))
602 (make-instance 'complex-bigfloat
604 (maxima::fptimes
* (cdr (real-value a
))
605 (cdr (intofp (realpart b
)))))
607 (maxima::fptimes
* (cdr (real-value a
))
608 (cdr (intofp (imagpart b
)))))))
610 (defmethod two-arg-* ((a cl
:number
) (b bigfloat
))
613 (defmethod two-arg-* ((a complex-bigfloat
) (b bigfloat
))
614 (make-instance 'complex-bigfloat
616 (maxima::fptimes
* (cdr (real-value a
))
617 (cdr (real-value b
))))
619 (maxima::fptimes
* (cdr (imag-value a
))
620 (cdr (real-value b
))))))
622 (defmethod two-arg-* ((a complex-bigfloat
) (b number
))
624 (two-arg-* a
(bigfloat (cl:realpart b
) (cl:imagpart b
)))
625 (two-arg-* a
(bigfloat b
))))
627 (defmethod two-arg-* ((a bigfloat
) (b complex-bigfloat
))
630 (defmethod two-arg-* ((a number
) (b complex-bigfloat
))
633 (defun * (&rest args
)
636 (do ((args (cdr args
) (cdr args
))
638 (two-arg-* res
(car args
))))
641 ;;; Reciprocal of a number
642 (defmethod unary-divide ((a number
))
645 (defmethod unary-divide ((a bigfloat
))
646 (make-instance 'bigfloat
648 (maxima::fpquotient
(maxima::fpone
)
649 (cdr (real-value a
))))))
651 (defmethod unary-divide ((b complex-bigfloat
))
652 ;; Could just call two-arg-/, but let's optimize this a little
653 (let ((a-re (maxima::fpone
))
654 (b-re (cdr (real-value b
)))
655 (b-im (cdr (imag-value b
))))
656 (if (maxima::fpgreaterp
(maxima::fpabs b-re
) (maxima::fpabs b-im
))
657 (let* ((r (maxima::fpquotient b-im b-re
))
658 (dn (maxima::fpplus b-re
(maxima::fptimes
* r b-im
))))
659 (make-instance 'complex-bigfloat
660 :real
(maxima::bcons
(maxima::fpquotient a-re dn
))
662 (maxima::fpquotient
(maxima::fpminus r
)
664 (let* ((r (maxima::fpquotient b-re b-im
))
665 (dn (maxima::fpplus b-im
(maxima::fptimes
* r b-re
))))
666 (make-instance 'complex-bigfloat
667 :real
(maxima::bcons
(maxima::fpquotient r dn
))
669 (maxima::fpquotient
(maxima::fpminus a-re
)
671 ;;; Divide two numbers
672 (defmethod two-arg-/ ((a number
) (b number
))
675 (defmethod two-arg-/ ((a bigfloat
) (b bigfloat
))
676 (make-instance 'bigfloat
678 (maxima::fpquotient
(cdr (real-value a
))
679 (cdr (real-value b
))))))
681 (defmethod two-arg-/ ((a complex-bigfloat
) (b complex-bigfloat
))
682 (let ((a-re (cdr (real-value a
)))
683 (a-im (cdr (imag-value a
)))
684 (b-re (cdr (real-value b
)))
685 (b-im (cdr (imag-value b
))))
686 (if (maxima::fpgreaterp
(maxima::fpabs b-re
) (maxima::fpabs b-im
))
687 (let* ((r (maxima::fpquotient b-im b-re
))
688 (dn (maxima::fpplus b-re
(maxima::fptimes
* r b-im
))))
689 (make-instance 'complex-bigfloat
693 (maxima::fptimes
* a-im r
))
697 (maxima::fpdifference a-im
698 (maxima::fptimes
* a-re r
))
700 (let* ((r (maxima::fpquotient b-re b-im
))
701 (dn (maxima::fpplus b-im
(maxima::fptimes
* r b-re
))))
702 (make-instance 'complex-bigfloat
705 (maxima::fpplus
(maxima::fptimes
* a-re r
)
709 (maxima::fpquotient
(maxima::fpdifference
710 (maxima::fptimes
* a-im r
)
713 ;; Handle contagion for two-arg-/
714 (defmethod two-arg-/ ((a bigfloat
) (b cl
:float
))
715 (make-instance 'bigfloat
717 (maxima::fpquotient
(cdr (real-value a
))
720 (defmethod two-arg-/ ((a bigfloat
) (b cl
:rational
))
721 (make-instance 'bigfloat
723 (maxima::fpquotient
(cdr (real-value a
))
726 (defmethod two-arg-/ ((a bigfloat
) (b cl
:complex
))
727 (two-arg-/ (complex a
) b
))
729 (defmethod two-arg-/ ((a cl
:float
) (b bigfloat
))
730 (make-instance 'bigfloat
732 (maxima::fpquotient
(cdr (intofp a
))
733 (cdr (real-value b
))))))
735 (defmethod two-arg-/ ((a cl
:rational
) (b bigfloat
))
736 (make-instance 'bigfloat
738 (maxima::fpquotient
(cdr (intofp a
))
739 (cdr (real-value b
))))))
741 (defmethod two-arg-/ ((a cl
:complex
) (b bigfloat
))
742 (two-arg-/ (bigfloat a
) b
))
745 (defmethod two-arg-/ ((a complex-bigfloat
) (b bigfloat
))
746 (make-instance 'complex-bigfloat
748 (maxima::fpquotient
(cdr (real-value a
))
749 (cdr (real-value b
))))
751 (maxima::fpquotient
(cdr (imag-value a
))
752 (cdr (real-value b
))))))
754 (defmethod two-arg-/ ((a complex-bigfloat
) (b number
))
756 (two-arg-/ a
(bigfloat (cl:realpart b
) (cl:imagpart b
)))
757 (two-arg-/ a
(bigfloat b
))))
759 (defmethod two-arg-/ ((a bigfloat
) (b complex-bigfloat
))
760 (two-arg-/ (make-instance 'complex-bigfloat
:real
(real-value a
))
763 (defmethod two-arg-/ ((a number
) (b complex-bigfloat
))
765 (two-arg-/ (bigfloat (cl:realpart a
) (cl:imagpart a
))
767 (two-arg-/ (bigfloat a
) b
)))
770 (defun / (number &rest more-numbers
)
772 (do ((nlist more-numbers
(cdr nlist
))
774 ((atom nlist
) result
)
775 (declare (list nlist
))
776 (setq result
(two-arg-/ result
(car nlist
))))
777 (unary-divide number
)))
779 ;;; Compare against zero (zerop, minusp, plusp)
782 (let ((cl-name (intern (symbol-name name
) :cl
)))
784 (defmethod ,name
((x cl
:float
))
786 (defmethod ,name
((x cl
:rational
))
791 (defmethod zerop ((x number
))
794 (defmethod zerop ((x bigfloat
))
795 (let ((r (cdr (real-value x
))))
796 (and (zerop (first r
))
797 (zerop (second r
)))))
799 (defmethod zerop ((a complex-bigfloat
))
800 (and (equal (cdr (real-value a
)) '(0 0))
801 (equal (cdr (imag-value a
)) '(0 0))))
803 (defmethod plusp ((x bigfloat
))
804 (cl:plusp
(first (cdr (real-value x
)))))
806 (defmethod minusp ((x bigfloat
))
807 (cl:minusp
(first (cdr (real-value x
)))))
812 (defmethod two-arg-= ((a number
) (b number
))
815 (defmethod two-arg-= ((a bigfloat
) (b bigfloat
))
816 (zerop (two-arg-- a b
)))
818 (defmethod two-arg-= ((a complex-bigfloat
) (b complex-bigfloat
))
819 (zerop (two-arg-- a b
)))
821 ;; Handle contagion for two-arg-=. This needs some work. CL says
822 ;; floats and rationals are compared by converting the float to a
823 ;; rational before converting.
824 (defmethod two-arg-= ((a bigfloat
) (b number
))
825 (zerop (two-arg-- a b
)))
827 (defmethod two-arg-= ((a number
) (b bigfloat
))
830 (defmethod two-arg-= ((a complex-bigfloat
) (b number
))
831 (zerop (two-arg-- a b
)))
833 (defmethod two-arg-= ((a number
) (b complex-bigfloat
))
836 (defun = (number &rest more-numbers
)
837 "Returns T if all of its arguments are numerically equal, NIL otherwise."
838 (declare (optimize (safety 2))
839 #-gcl
(dynamic-extent more-numbers
))
840 (do ((nlist more-numbers
(cdr nlist
)))
842 (declare (list nlist
))
843 (if (not (two-arg-= (car nlist
) number
))
846 (defun /= (number &rest more-numbers
)
847 "Returns T if no two of its arguments are numerically equal, NIL otherwise."
848 (declare (optimize (safety 2))
849 #-gcl
(dynamic-extent more-numbers
))
850 (do* ((head number
(car nlist
))
851 (nlist more-numbers
(cdr nlist
)))
853 (declare (list nlist
))
854 (unless (do* ((nl nlist
(cdr nl
)))
857 (if (two-arg-= head
(car nl
))
861 ;;; Comparison operations
864 (let ((method (intern (concatenate 'string
867 (cl-fun (find-symbol (symbol-name op
) :cl
)))
869 (defmethod ,method
((a cl
:float
) (b cl
:float
))
871 (defmethod ,method
((a cl
:float
) (b cl
:rational
))
873 (defmethod ,method
((a cl
:rational
) (b cl
:float
))
875 (defmethod ,method
((a cl
:rational
) (b cl
:rational
))
877 (defun ,op
(number &rest more-numbers
)
878 "Returns T if its arguments are in strictly increasing order, NIL otherwise."
879 (declare (optimize (safety 2))
880 #-gcl
(dynamic-extent more-numbers
))
881 (do* ((n number
(car nlist
))
882 (nlist more-numbers
(cdr nlist
)))
884 (declare (list nlist
))
885 (if (not (,method n
(car nlist
))) (return nil
))))))))
891 (defmethod two-arg-< ((x bigfloat
) (y bigfloat
))
892 (maxima::fplessp
(cdr (real-value x
)) (cdr (real-value y
))))
894 (defmethod two-arg-< ((x bigfloat
) (y cl
:float
))
895 (maxima::fplessp
(cdr (real-value x
)) (cdr (intofp y
))))
897 (defmethod two-arg-< ((x bigfloat
) (y cl
:rational
))
898 (maxima::fplessp
(cdr (real-value x
)) (cdr (intofp y
))))
900 (defmethod two-arg-< ((x cl
:float
) (y bigfloat
))
901 (maxima::fplessp
(cdr (intofp x
)) (cdr (real-value y
))))
903 (defmethod two-arg-< ((x cl
:rational
) (y bigfloat
))
904 (maxima::fplessp
(cdr (intofp x
)) (cdr (real-value y
))))
906 (defmethod two-arg-> ((x bigfloat
) (y bigfloat
))
907 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (real-value y
))))
909 (defmethod two-arg-> ((x bigfloat
) (y cl
:float
))
910 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (intofp y
))))
912 (defmethod two-arg-> ((x bigfloat
) (y cl
:rational
))
913 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (intofp y
))))
915 (defmethod two-arg-> ((x cl
:float
) (y bigfloat
))
916 (maxima::fpgreaterp
(cdr (intofp x
)) (cdr (real-value y
))))
918 (defmethod two-arg-> ((x cl
:rational
) (y bigfloat
))
919 (maxima::fpgreaterp
(cdr (intofp x
)) (cdr (real-value y
))))
921 (defmethod two-arg-<= ((x bigfloat
) (y bigfloat
))
922 (or (zerop (two-arg-- x y
))
923 (maxima::fplessp
(cdr (real-value x
)) (cdr (real-value y
)))))
925 (defmethod two-arg-<= ((x bigfloat
) (y cl
:float
))
926 (or (zerop (two-arg-- x y
))
927 (maxima::fplessp
(cdr (real-value x
)) (cdr (intofp y
)))))
929 (defmethod two-arg-<= ((x bigfloat
) (y cl
:rational
))
930 (or (zerop (two-arg-- x y
))
931 (maxima::fplessp
(cdr (real-value x
)) (cdr (intofp y
)))))
933 (defmethod two-arg-<= ((x cl
:float
) (y bigfloat
))
934 (or (zerop (two-arg-- x y
))
935 (maxima::fplessp
(cdr (intofp x
)) (cdr (real-value y
)))))
937 (defmethod two-arg-<= ((x cl
:rational
) (y bigfloat
))
938 (or (zerop (two-arg-- x y
))
939 (maxima::fplessp
(cdr (intofp x
)) (cdr (real-value y
)))))
941 (defmethod two-arg->= ((x bigfloat
) (y bigfloat
))
942 (or (zerop (two-arg-- x y
))
943 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (real-value y
)))))
945 (defmethod two-arg->= ((x bigfloat
) (y cl
:float
))
946 (or (zerop (two-arg-- x y
))
947 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (intofp y
)))))
949 (defmethod two-arg->= ((x bigfloat
) (y cl
:rational
))
950 (or (zerop (two-arg-- x y
))
951 (maxima::fpgreaterp
(cdr (real-value x
)) (cdr (intofp y
)))))
953 (defmethod two-arg->= ((x cl
:float
) (y bigfloat
))
954 (or (zerop (two-arg-- x y
))
955 (maxima::fpgreaterp
(cdr (intofp x
)) (cdr (real-value y
)))))
957 (defmethod two-arg->= ((x cl
:rational
) (y bigfloat
))
958 (or (zerop (two-arg-- x y
))
959 (maxima::fpgreaterp
(cdr (intofp x
)) (cdr (real-value y
)))))
961 ;; Need to define incf and decf to call our generic +/- methods.
962 (defmacro incf
(place &optional
(delta 1) &environment env
)
963 "The first argument is some location holding a number. This number is
964 incremented by the second argument, DELTA, which defaults to 1."
965 (multiple-value-bind (dummies vals newval setter getter
)
966 (get-setf-expansion place env
)
968 `(let* (,@(mapcar #'list dummies vals
)
970 (,(car newval
) (+ ,getter
,d
)))
973 (defmacro decf
(place &optional
(delta 1) &environment env
)
974 "The first argument is some location holding a number. This number is
975 decremented by the second argument, DELTA, which defaults to 1."
976 (multiple-value-bind (dummies vals newval setter getter
)
977 (get-setf-expansion place env
)
979 `(let* (,@(mapcar #'list dummies vals
)
981 (,(car newval
) (- ,getter
,d
)))
986 ;;; Special functions for real-valued arguments
989 (let ((cl-name (intern (symbol-name name
) :cl
)))
991 (defmethod ,name
((x number
))
1009 (defmethod abs ((x bigfloat
))
1010 (make-instance 'bigfloat
1011 :real
(maxima::bcons
(maxima::fpabs
(cdr (real-value x
))))))
1013 (defmethod abs ((z complex-bigfloat
))
1014 (let ((x (make-instance 'bigfloat
:real
(real-value z
)))
1015 (y (make-instance 'bigfloat
:real
(imag-value z
))))
1016 ;; Bigfloats don't overflow, so we don't need anything special.
1017 (sqrt (+ (* x x
) (* y y
)))))
1019 (defmethod exp ((x bigfloat
))
1020 (make-instance 'bigfloat
1021 :real
(maxima::bcons
(maxima::fpexp
(cdr (real-value x
))))))
1023 (defmethod sin ((x bigfloat
))
1024 (make-instance 'bigfloat
1025 :real
(maxima::bcons
(maxima::fpsin
(cdr (real-value x
)) t
))))
1027 (defmethod cos ((x bigfloat
))
1028 (make-instance 'bigfloat
1029 :real
(maxima::bcons
(maxima::fpsin
(cdr (real-value x
)) nil
))))
1031 (defmethod tan ((x bigfloat
))
1032 (let ((r (cdr (real-value x
))))
1033 (make-instance 'bigfloat
1034 :real
(maxima::bcons
1035 (maxima::fpquotient
(maxima::fpsin r t
)
1036 (maxima::fpsin r nil
))))))
1038 (defmethod asin ((x bigfloat
))
1039 (bigfloat (maxima::fpasin
(real-value x
))))
1041 (defmethod acos ((x bigfloat
))
1042 (bigfloat (maxima::fpacos
(real-value x
))))
1045 (defmethod sqrt ((x bigfloat
))
1047 (make-instance 'complex-bigfloat
1049 :imag
(maxima::bcons
1050 (maxima::fproot
(maxima::bcons
(maxima::fpabs
(cdr (real-value x
)))) 2)))
1051 (make-instance 'bigfloat
1052 :real
(maxima::bcons
1053 (maxima::fproot
(real-value x
) 2)))))
1055 (defmethod sqrt ((z complex-bigfloat
))
1056 (multiple-value-bind (rx ry
)
1057 (maxima::complex-sqrt
(real-value z
)
1059 (make-instance 'complex-bigfloat
1060 :real
(maxima::bcons rx
)
1061 :imag
(maxima::bcons ry
))))
1063 (defmethod one-arg-log ((a number
))
1066 (defmethod one-arg-log ((a bigfloat
))
1068 (make-instance 'complex-bigfloat
1069 :real
(maxima::bcons
1070 (maxima::fplog
(maxima::fpabs
(cdr (real-value a
)))))
1071 :imag
(maxima::bcons
(maxima::fppi
)))
1072 (make-instance 'bigfloat
1073 :real
(maxima::bcons
(maxima::fplog
(cdr (real-value a
)))))))
1075 (defmethod one-arg-log ((a complex-bigfloat
))
1076 (let* ((res (maxima::big-float-log
(real-value a
)
1080 (defmethod two-arg-log ((a number
) (b number
))
1083 (defmethod two-arg-log ((a numeric
) (b numeric
))
1084 (two-arg-/ (one-arg-log a
) (one-arg-log b
)))
1086 (defmethod two-arg-log ((a numeric
) (b cl
:number
))
1087 (two-arg-/ (one-arg-log a
) (one-arg-log (bigfloat b
))))
1089 (defmethod two-arg-log ((a cl
:number
) (b numeric
))
1090 (two-arg-/ (one-arg-log (bigfloat a
)) (one-arg-log b
)))
1092 (defun log (a &optional b
)
1097 (defmethod sinh ((x bigfloat
))
1098 (let ((r (real-value x
)))
1099 (make-instance 'bigfloat
:real
(maxima::fpsinh r
))))
1101 (defmethod cosh ((x bigfloat
))
1102 (let ((r (real-value x
)))
1103 (make-instance 'bigfloat
:real
(maxima::$bfloat
`((maxima::%cosh
) ,r
)))))
1105 (defmethod tanh ((x bigfloat
))
1106 (let ((r (real-value x
)))
1107 (make-instance 'bigfloat
:real
(maxima::fptanh r
))))
1109 (defmethod asinh ((x bigfloat
))
1110 (let ((r (real-value x
)))
1111 (make-instance 'bigfloat
:real
(maxima::fpasinh r
))))
1113 (defmethod atanh ((x bigfloat
))
1114 (let ((r (maxima::big-float-atanh
(real-value x
))))
1115 (if (maxima::bigfloatp r
)
1116 (make-instance 'bigfloat
:real r
)
1117 (make-instance 'complex-bigfloat
1118 :real
(maxima::$realpart r
)
1119 :imag
(maxima::$imagpart r
)))))
1121 (defmethod acosh ((x bigfloat
))
1122 (let* ((r (real-value x
))
1123 (value (maxima::meval
`((maxima::%acosh maxima
::simp
) ,r
))))
1124 (if (maxima::bigfloatp value
)
1125 (make-instance 'bigfloat
:real value
)
1126 (make-instance 'complex-bigfloat
1127 :real
(maxima::$realpart value
)
1128 :imag
(maxima::$imagpart value
)))))
1130 ;;; Complex arguments
1132 ;;; Special functions for complex args
1134 ((frob (name &optional big-float-op-p
)
1136 (let ((big-op (intern (concatenate 'string
1137 (string '#:big-float-
)
1140 `(defmethod ,name
((a complex-bigfloat
))
1141 (let ((res (,big-op
(real-value a
)
1144 (let ((max-op (intern (concatenate 'string
"$" (string name
)) '#:maxima
)))
1145 `(defmethod ,name
((a complex-bigfloat
))
1146 ;; We should do something better than calling meval
1147 (let* ((arg (maxima::add
(real-value a
)
1148 (maxima::mul
'maxima
::$%i
(imag-value a
))))
1149 (result (maxima::meval
`((,',max-op maxima
::simp
) ,arg
))))
1164 (defmethod one-arg-atan ((a number
))
1167 (defmethod one-arg-atan ((a bigfloat
))
1168 (make-instance 'bigfloat
1169 :real
(maxima::bcons
(maxima::fpatan
(cdr (real-value a
))))))
1171 (defmethod one-arg-atan ((a complex-bigfloat
))
1172 ;; We should do something better than calling meval
1173 (let* ((arg (maxima::add
(real-value a
)
1174 (maxima::mul
'maxima
::$%i
(imag-value a
))))
1175 (result (maxima::meval
`((maxima::%atan maxima
::simp
) ,arg
))))
1176 (make-instance 'complex-bigfloat
1177 :real
(maxima::$realpart result
)
1178 :imag
(maxima::$imagpart result
))))
1180 ;; Really want type real, but gcl doesn't like that. Define methods for rational and float
1182 (defmethod two-arg-atan ((a real
) (b real
))
1187 (defmethod two-arg-atan ((a cl
:float
) (b cl
:float
))
1189 (defmethod two-arg-atan ((a cl
:rational
) (b cl
:rational
))
1191 (defmethod two-arg-atan ((a cl
:float
) (b cl
:rational
))
1193 (defmethod two-arg-atan ((a cl
:rational
) (b cl
:float
))
1197 (defmethod two-arg-atan ((a bigfloat
) (b bigfloat
))
1198 (make-instance 'bigfloat
1199 :real
(maxima::bcons
1200 (maxima::fpatan2
(cdr (real-value a
))
1201 (cdr (real-value b
))))))
1203 (defmethod two-arg-atan ((a bigfloat
) (b cl
:float
))
1204 (make-instance 'bigfloat
1205 :real
(maxima::bcons
(maxima::fpatan2
(cdr (real-value a
))
1206 (cdr (intofp b
))))))
1208 (defmethod two-arg-atan ((a bigfloat
) (b cl
:rational
))
1209 (make-instance 'bigfloat
1210 :real
(maxima::bcons
(maxima::fpatan2
(cdr (real-value a
))
1211 (cdr (intofp b
))))))
1213 (defmethod two-arg-atan ((a cl
:float
) (b bigfloat
))
1214 (make-instance 'bigfloat
1215 :real
(maxima::bcons
(maxima::fpatan2
(cdr (intofp a
))
1216 (cdr (real-value b
))))))
1218 (defmethod two-arg-atan ((a cl
:rational
) (b bigfloat
))
1219 (make-instance 'bigfloat
1220 :real
(maxima::bcons
(maxima::fpatan2
(cdr (intofp a
))
1221 (cdr (real-value b
))))))
1223 (defun atan (a &optional b
)
1228 (defmethod scale-float ((a cl
:float
) (n integer
))
1229 (cl:scale-float a n
))
1231 (defmethod scale-float ((a bigfloat
) (n integer
))
1232 (if (cl:zerop
(second (real-value a
)))
1233 (make-instance 'bigfloat
:real
(maxima::bcons
(list 0 0)))
1234 (destructuring-bind (marker mantissa exp
)
1236 (declare (ignore marker
))
1237 (make-instance 'bigfloat
:real
(maxima::bcons
(list mantissa
(+ exp n
)))))))
1241 (let ((cl-name (intern (string name
) '#:cl
)))
1242 `(defmethod ,name
((a number
))
1251 (let ((cl-name (intern (string name
) '#:cl
)))
1252 `(defmethod ,name
((a number
) &optional
(divisor 1))
1253 (,cl-name a divisor
)))))
1264 (defmethod realpart ((a bigfloat
))
1265 (make-instance 'bigfloat
:real
(real-value a
)))
1267 (defmethod realpart ((a complex-bigfloat
))
1268 (make-instance 'bigfloat
:real
(real-value a
)))
1270 (defmethod imagpart ((a bigfloat
))
1271 (make-instance 'bigfloat
:real
(intofp 0)))
1273 (defmethod imagpart ((a complex-bigfloat
))
1274 (make-instance 'bigfloat
:real
(imag-value a
)))
1276 (defmethod conjugate ((a bigfloat
))
1277 (make-instance 'bigfloat
:real
(real-value a
)))
1279 (defmethod conjugate ((a complex-bigfloat
))
1280 (make-instance 'complex-bigfloat
1281 :real
(real-value a
)
1282 :imag
(maxima::bcons
(maxima::fpminus
(cdr (imag-value a
))))))
1284 (defmethod cis ((a cl
:float
))
1287 (defmethod cis ((a cl
:rational
))
1290 (defmethod cis ((a bigfloat
))
1291 (make-instance 'complex-bigfloat
1292 :real
(maxima::bcons
(maxima::fpsin
(cdr (real-value a
)) nil
))
1293 :imag
(maxima::bcons
(maxima::fpsin
(cdr (real-value a
)) t
))))
1295 (defmethod phase ((a bigfloat
))
1296 (let ((r (cdr (real-value a
))))
1297 (if (cl:>= (car r
) 0)
1298 (make-instance 'bigfloat
:real
(maxima::bcons
(list 0 0)))
1299 (make-instance 'bigfloat
:real
(maxima::bcons
(maxima::fppi
))))))
1301 (defmethod phase ((a complex-bigfloat
))
1302 (make-instance 'bigfloat
1303 :real
(maxima::bcons
(maxima::fpatan2
(cdr (imag-value a
))
1304 (cdr (real-value a
))))))
1306 (defun max (number &rest more-numbers
)
1307 "Returns the greatest of its arguments."
1308 (declare (optimize (safety 2)) (type (or real bigfloat
) number
)
1309 #-gcl
(dynamic-extent more-numbers
))
1310 (dolist (real more-numbers
)
1311 (when (> real number
)
1312 (setq number real
)))
1315 (defun min (number &rest more-numbers
)
1316 "Returns the least of its arguments."
1317 (declare (optimize (safety 2)) (type (or real bigfloat
) number
)
1318 #-gcl
(dynamic-extent more-numbers
))
1319 (do ((nlist more-numbers
(cdr nlist
))
1320 (result (the (or real bigfloat
) number
)))
1321 ((null nlist
) (return result
))
1322 (declare (list nlist
))
1323 (if (< (car nlist
) result
)
1324 (setq result
(car nlist
)))))
1326 ;; We really want a real type, but gcl doesn't like it, so use number
1329 (defmethod one-arg-complex ((a real
))
1334 (defmethod one-arg-complex ((a cl
:float
))
1336 (defmethod one-arg-complex ((a cl
:rational
))
1340 (defmethod one-arg-complex ((a bigfloat
))
1341 (make-instance 'complex-bigfloat
1342 :real
(real-value a
)
1346 (defmethod two-arg-complex ((a real
) (b real
))
1351 (defmethod two-arg-complex ((a cl
:float
) (b cl
:float
))
1353 (defmethod two-arg-complex ((a cl
:rational
) (b cl
:rational
))
1355 (defmethod two-arg-complex ((a cl
:float
) (b cl
:rational
))
1357 (defmethod two-arg-complex ((a cl
:rational
) (b cl
:float
))
1361 (defmethod two-arg-complex ((a bigfloat
) (b bigfloat
))
1362 (make-instance 'complex-bigfloat
1363 :real
(real-value a
)
1364 :imag
(real-value b
)))
1366 (defmethod two-arg-complex ((a cl
:float
) (b bigfloat
))
1367 (make-instance 'complex-bigfloat
1369 :imag
(real-value b
)))
1371 (defmethod two-arg-complex ((a cl
:rational
) (b bigfloat
))
1372 (make-instance 'complex-bigfloat
1374 :imag
(real-value b
)))
1376 (defmethod two-arg-complex ((a bigfloat
) (b cl
:float
))
1377 (make-instance 'complex-bigfloat
1378 :real
(real-value a
)
1381 (defmethod two-arg-complex ((a bigfloat
) (b cl
:rational
))
1382 (make-instance 'complex-bigfloat
1383 :real
(real-value a
)
1386 (defun complex (a &optional b
)
1388 (two-arg-complex a b
)
1389 (one-arg-complex a
)))
1391 (defmethod unary-floor ((a bigfloat
))
1392 ;; fpentier truncates to zero, so adjust for negative numbers
1393 (let ((trunc (maxima::fpentier
(real-value a
))))
1395 ;; If the truncated value is the same as the original,
1396 ;; there's nothing to do because A was an integer.
1397 ;; Otherwise, we need to subtract 1 to make it the floor.
1404 (defmethod unary-ffloor ((a bigfloat
))
1405 ;; We can probably do better than converting to an integer and
1406 ;; converting back to a float.
1407 (make-instance 'bigfloat
:real
(intofp (unary-floor a
))))
1409 (defmethod floor ((a bigfloat
) &optional
(divisor 1))
1411 (let ((int (unary-floor a
)))
1412 (values int
(- a int
)))
1413 (let ((q (unary-floor (/ a divisor
))))
1414 (values q
(- a
(* q divisor
))))))
1416 (defmethod ffloor ((a bigfloat
) &optional
(divisor 1))
1418 (let ((int (unary-ffloor a
)))
1419 (values int
(- a int
)))
1420 (let ((q (unary-ffloor (/ a divisor
))))
1421 (values q
(- a
(* q divisor
))))))
1423 (defmethod unary-truncate ((a bigfloat
))
1424 (maxima::fpentier
(real-value a
)))
1426 (defmethod unary-ftruncate ((a bigfloat
))
1427 ;; We can probably do better than converting to an integer and
1428 ;; converting back to a float.
1429 (make-instance 'bigfloat
:real
(intofp (unary-truncate a
))))
1431 (defmethod truncate ((a bigfloat
) &optional
(divisor 1))
1433 (let ((int (unary-truncate a
)))
1434 (values int
(- a int
)))
1435 (let ((q (unary-truncate (/ a divisor
))))
1436 (values q
(- a
(* q divisor
))))))
1438 (defmethod ftruncate ((a bigfloat
) &optional
(divisor 1))
1440 (let ((int (unary-ftruncate a
)))
1441 (values int
(- a int
)))
1442 (let ((q (unary-ftruncate (/ a divisor
))))
1443 (values q
(- a
(* q divisor
))))))
1445 (defmethod unary-ceiling ((a bigfloat
))
1446 ;; fpentier truncates to zero, so adjust for positive numbers.
1448 (maxima::fpentier
(real-value a
))
1449 (maxima::fpentier
(real-value (+ a
1)))))
1451 (defmethod unary-fceiling ((a bigfloat
))
1452 ;; We can probably do better than converting to an integer and
1453 ;; converting back to a float.
1454 (make-instance 'bigfloat
:real
(intofp (unary-ceiling a
))))
1456 (defmethod ceiling ((a bigfloat
) &optional
(divisor 1))
1458 (let ((int (unary-ceiling a
)))
1459 (values int
(- a int
)))
1460 (let ((q (unary-ceiling (/ a divisor
))))
1461 (values q
(- a
(* q divisor
))))))
1463 (defmethod fceiling ((a bigfloat
) &optional
(divisor 1))
1465 (let ((int (unary-fceiling a
)))
1466 (values int
(- a int
)))
1467 (let ((q (unary-fceiling (/ a divisor
))))
1468 (values q
(- a
(* q divisor
))))))
1470 ;; Stolen from CMUCL.
1471 (defmethod round ((a bigfloat
) &optional
(divisor 1))
1472 (multiple-value-bind (tru rem
)
1473 (truncate a divisor
)
1476 (let ((thresh (/ (abs divisor
) 2)))
1477 (cond ((or (> rem thresh
)
1478 (and (= rem thresh
) (oddp tru
)))
1479 (if (minusp divisor
)
1480 (values (- tru
1) (+ rem divisor
))
1481 (values (+ tru
1) (- rem divisor
))))
1482 ((let ((-thresh (- thresh
)))
1484 (and (= rem -thresh
) (oddp tru
))))
1485 (if (minusp divisor
)
1486 (values (+ tru
1) (- rem divisor
))
1487 (values (- tru
1) (+ rem divisor
))))
1488 (t (values tru rem
)))))))
1490 (defmethod fround ((number bigfloat
) &optional
(divisor 1))
1491 "Same as ROUND, but returns first value as a float."
1492 (multiple-value-bind (res rem
)
1493 (round number divisor
)
1494 (values (bigfloat res
) rem
)))
1496 (defmethod expt ((a number
) (b number
))
1499 ;; This needs more work
1500 (defmethod expt ((a numeric
) (b numeric
))
1502 ;; CLHS says if the power is 0, the answer is 1 of the appropriate type.
1503 (if (or (typep a
'complex-bigfloat
)
1504 (typep b
'complex-bigfloat
))
1505 (complex (bigfloat 1))
1507 (cond ((and (zerop a
) (plusp (realpart b
)))
1509 ((and (realp b
) (= b
(truncate b
)))
1510 ;; Use the numeric^number method because it can be much
1511 ;; more accurate when b is an integer.
1512 (expt a
(truncate b
)))
1514 (with-extra-precision ((expt-extra-bits a b
)
1516 (exp (* b
(log a
))))))))
1518 (defmethod expt ((a cl
:number
) (b numeric
))
1520 ;; CLHS says if the power is 0, the answer is 1 of the appropriate type.
1521 (if (or (typep a
'cl
:complex
)
1522 (typep b
'complex-bigfloat
))
1523 (complex (bigfloat 1))
1525 (cond ((and (zerop a
) (plusp (realpart b
)))
1527 ((and (realp b
) (= b
(truncate b
)))
1528 (with-extra-precision ((expt-extra-bits a b
)
1530 (intofp (expt a
(truncate b
)))))
1532 (with-extra-precision ((expt-extra-bits a b
)
1534 (exp (* b
(log (bigfloat a
)))))))))
1536 (defmethod expt ((a numeric
) (b cl
:number
))
1538 ;; CLHS says if the power is 0, the answer is 1 of the appropriate type.
1539 (if (or (typep a
'complex-bigfloat
)
1540 (typep b
'cl
:complex
))
1541 (complex (bigfloat 1))
1543 (if (and (zerop a
) (plusp (realpart b
)))
1545 ;; Handle a few special cases using multiplication.
1555 ((= b -
3) (/ (* a a a
)))
1563 (with-extra-precision ((expt-extra-bits a b
)
1565 (exp (* (bigfloat b
) (log a
)))))))))
1567 ;; Handle a^b a little more carefully because the result is known to
1568 ;; be real when a is real and b is an integer.
1569 (defmethod expt ((a bigfloat
) (b integer
))
1572 ((and (zerop a
) (plusp b
))
1573 ;; 0^b, for positive b
1575 ;; Handle a few special cases using multiplication.
1579 ((eql b -
2) (/ (* a a
)))
1580 ((eql b
3) (* a a a
))
1581 ((eql b -
3) (/ (* a a a
)))
1589 ;; a^b = exp(b*log(|a|) + %i*%pi*b)
1590 ;; = exp(b*log(|a|))*exp(%i*%pi*b)
1591 ;; = (-1)^b*exp(b*log(|a|))
1592 (with-extra-precision ((expt-extra-bits a b
)
1594 (* (exp (* b
(log (abs a
))))
1595 (if (oddp b
) -
1 1))))
1597 (with-extra-precision ((expt-extra-bits a b
)
1599 (exp (* b
(log a
)))))))
1603 ;;; TO takes a maxima number and converts it. Floats remain
1604 ;;; floats, maxima cl:rationals are converted to CL cl:rationals. Maxima
1605 ;;; bigfloats are convert to BIGFLOATS. Maxima complex numbers are
1606 ;;; converted to CL complex numbers or to COMPLEX-BIGFLOAT's.
1607 (defun to (maxima-num &optional imag
)
1608 (let ((result (ignore-errors (%to maxima-num imag
))))
1610 (maxima::merror
(intl:gettext
"BIGFLOAT: unable to convert ~M to a CL or BIGFLOAT number.")
1612 (maxima::add maxima-num
(maxima::mul imag
'maxima
::$%i
))
1615 ;;; MAYBE-TO - External
1617 ;;; Like TO, but if the maxima number can't be converted to a CL
1618 ;;; number or BIGFLOAT, just return the maxima number.
1619 (defun maybe-to (maxima-num &optional imag
)
1620 (let ((result (ignore-errors (%to maxima-num imag
))))
1623 (maxima::add maxima-num imag
)
1626 (defun %to
(maxima-num &optional imag
)
1628 ;; Clisp has a "feature" that (complex rat float) does not
1629 ;; make the both components of the complex number a float.
1630 ;; Sometimes this is nice, but other times it's annoying
1631 ;; because it is non-ANSI behavior. For our code, we really
1632 ;; want both components to be a float.
1634 (complex (to maxima-num
) (to imag
))
1636 (let ((re (to maxima-num
))
1638 (cond ((and (rationalp re
) (floatp im
))
1639 (setf re
(float re im
)))
1640 ((and (rational im
) (floatp re
))
1641 (setf im
(float im re
))))
1644 (cond ((cl:numberp maxima-num
)
1646 ((eq maxima-num
'maxima
::$%i
)
1647 ;; Convert %i to an exact complex cl:rational.
1650 ;; Some kind of maxima number
1651 (cond ((maxima::ratnump maxima-num
)
1652 ;; Maxima cl:rational ((mrat ...) num den)
1653 (/ (second maxima-num
) (third maxima-num
)))
1654 ((maxima::$bfloatp maxima-num
)
1655 (bigfloat maxima-num
))
1656 ((maxima::complex-number-p maxima-num
#'(lambda (x)
1658 (maxima::$bfloatp x
)
1660 (eq (caar x
) 'maxima
::rat
)))))
1661 ;; We have some kind of complex number whose
1662 ;; parts are a cl:real, a bfloat, or a Maxima
1664 (let ((re (maxima::$realpart maxima-num
))
1665 (im (maxima::$imagpart maxima-num
)))
1667 ((or (typep maxima-num
'bigfloat
)
1668 (typep maxima-num
'complex-bigfloat
))
1671 (error "BIGFLOAT: unable to convert to a CL or BIGFLOAT number."))))))
1673 ;;; EPSILON - External
1675 ;;; Return the float epsilon value for the given float type.
1676 (defmethod epsilon ((x cl
:float
))
1678 (short-float short-float-epsilon
)
1679 (single-float single-float-epsilon
)
1680 (double-float double-float-epsilon
)
1681 (long-float long-float-epsilon
)))
1683 (defmethod epsilon ((x cl
:complex
))
1684 (epsilon (cl:realpart x
)))
1686 (defmethod epsilon ((x bigfloat
))
1687 ;; epsilon is just above 2^(-fpprec).
1688 (make-instance 'bigfloat
1689 :real
(maxima::bcons
(list (1+ (ash 1 (1- maxima
::fpprec
)))
1690 (- (1- maxima
::fpprec
))))))
1692 (defmethod epsilon ((x complex-bigfloat
))
1693 (epsilon (realpart x
)))
1697 ;; Compiler macros to convert + to multiple calls to two-arg-+. Same
1699 (define-compiler-macro + (&whole form
&rest args
)
1700 (declare (ignore form
))
1703 (do ((args (cdr args
) (cdr args
))
1705 `(two-arg-+ ,res
,(car args
))))
1706 ((null args
) res
))))
1708 (define-compiler-macro -
(&whole form number
&rest more-numbers
)
1709 (declare (ignore form
))
1711 (do ((nlist more-numbers
(cdr nlist
))
1713 ((atom nlist
) result
)
1714 (declare (list nlist
))
1715 (setq result
`(two-arg-- ,result
,(car nlist
))))
1716 `(unary-minus ,number
)))
1718 (define-compiler-macro * (&whole form
&rest args
)
1719 (declare (ignore form
))
1722 (do ((args (cdr args
) (cdr args
))
1724 `(two-arg-* ,res
,(car args
))))
1725 ((null args
) res
))))
1727 (define-compiler-macro / (number &rest more-numbers
)
1729 (do ((nlist more-numbers
(cdr nlist
))
1731 ((atom nlist
) result
)
1732 (declare (list nlist
))
1733 (setq result
`(two-arg-/ ,result
,(car nlist
))))
1734 `(unary-divide ,number
)))
1736 (define-compiler-macro /= (&whole form number
&rest more-numbers
)
1737 ;; Convert (/= x y) to (not (two-arg-= x y)). Should we try to
1738 ;; handle a few more cases?
1739 (if (cdr more-numbers
)
1741 `(not (two-arg-= ,number
,(car more-numbers
)))))
1743 ;; Compiler macros to convert <, >, <=, and >= into multiple calls of
1744 ;; the corresponding two-arg-<foo> function.
1747 (let ((method (intern (concatenate 'string
1748 (string '#:two-arg-
)
1749 (symbol-name op
)))))
1750 `(define-compiler-macro ,op
(number &rest more-numbers
)
1751 (do* ((n number
(car nlist
))
1752 (nlist more-numbers
(cdr nlist
))
1755 `(and ,@(nreverse res
)))
1756 (push `(,',method
,n
,(car nlist
)) res
))))))
1762 (defmethod integer-decode-float ((x cl
:float
))
1763 (cl:integer-decode-float x
))
1765 (defmethod integer-decode-float ((x bigfloat
))
1766 (let ((r (real-value x
)))
1767 (values (abs (second r
))
1768 (- (third r
) (third (first r
)))
1769 (signum (second r
)))))
1771 (defmethod decode-float ((x cl
:float
))
1772 (cl:decode-float x
))
1774 (defmethod decode-float ((x bigfloat
))
1775 (let ((r (real-value x
)))
1776 (values (make-instance 'bigfloat
1777 :real
(maxima::bcons
(list (abs (second r
)) 0)))
1779 (bigfloat (signum (second r
))))))
1781 ;; GCL doesn't have a REAL class!
1784 (defmethod float ((x cl
:float
) (y cl
:float
))
1787 (defmethod float ((x cl
:rational
) (y cl
:float
))
1790 (defmethod float ((x cl
:float
) (y bigfloat
))
1793 (defmethod float ((x cl
:rational
) (y bigfloat
))
1799 (defmethod float ((x real
) (y cl
:float
))
1802 (defmethod float ((x real
) (y bigfloat
))
1806 ;; Like Maxima's fp2flo, but for single-float numbers.
1807 (defun fp2single (l)
1808 (let ((precision (caddar l
))
1810 (exponent (caddr l
))
1811 (fpprec (float-digits 1f0
))
1813 ;; Round the mantissa to the number of bits of precision of the
1814 ;; machine, and then convert it to a floating point fraction. We
1815 ;; have 0.5 <= mantissa < 1
1816 (setq mantissa
(maxima::quotient
(maxima::fpround mantissa
)
1818 ;; Multiply the mantissa by the exponent portion. I'm not sure
1819 ;; why the exponent computation is so complicated.
1821 ;; GCL doesn't signal overflow from scale-float if the number
1822 ;; would overflow. We have to do it this way. 0.5 <= mantissa <
1823 ;; 1. The largest double-float is .999999 * 2^128. So if the
1824 ;; exponent is 128 or higher, we have an overflow.
1825 (let ((e (+ exponent
(- precision
) maxima
::*m fpprec
)))
1826 (if (>= (abs e
) 129)
1827 (maxima::merror
(intl:gettext
"FP2SINGLE: floating point overflow converting ~:M to float.") l
)
1828 (cl:scale-float mantissa e
)))))
1831 (defmethod float ((x bigfloat
) (y cl
:float
))
1832 (if (typep y
'maxima
::flonum
)
1833 (maxima::fp2flo
(real-value x
))
1834 (fp2single (real-value x
))))
1836 (defmethod random ((x cl
:float
) &optional
(state cl
:*random-state
*))
1837 (cl:random x state
))
1838 (defmethod random ((x integer
) &optional
(state cl
:*random-state
*))
1839 (cl:random x state
))
1841 (defmethod random ((x bigfloat
) &optional
(state cl
:*random-state
*))
1842 ;; Generate an integer with fpprec bits, and convert to a bigfloat
1843 ;; by making the exponent 0. Then multiply by the arg to get the
1846 (let ((int (cl:random
(ash 1 maxima
::fpprec
) state
)))
1847 (* x
(bigfloat (maxima::bcons
(list int
0)))))
1848 (error "Argument is not a positive bigfloat: ~A~%" x
)))
1850 (defmethod signum ((x number
))
1853 (defmethod signum ((x bigfloat
))
1861 (defmethod signum ((x complex-bigfloat
))
1864 (defmethod float-sign ((x cl
:float
))
1867 (defmethod float-sign ((x bigfloat
))
1872 (defmethod float-digits ((x cl
:float
))
1873 (cl:float-digits x
))
1875 (defmethod float-digits ((x bigfloat
))
1876 ;; Should we just return fpprec or should we get the actual number
1877 ;; of bits in the bigfloat number? We choose the latter in case the
1878 ;; number and fpprec don't match.
1879 (let ((r (slot-value x
'real
)))
1883 (defmethod rational ((x real
))
1888 (defmethod rational ((x cl
:float
))
1890 (defmethod rational ((x cl
:rational
))
1894 (defmethod rational ((x bigfloat
))
1895 (destructuring-bind ((marker simp prec
) mantissa exp
)
1897 (declare (ignore marker simp
))
1898 (* mantissa
(expt 2 (- exp prec
)))))
1901 (defmethod rationalize ((x real
))
1906 (defmethod rationalize ((x cl
:float
))
1908 (defmethod rationalize ((x cl
:rational
))
1913 ;;; This routine taken from CMUCL, which, in turn is a routine from
1914 ;;; CLISP, which is GPL.
1916 ;;; I (rtoy) have modified it from CMUCL so that it only handles bigfloats.
1918 ;;; RATIONALIZE -- Public
1920 ;;; The algorithm here is the method described in CLISP. Bruno Haible has
1921 ;;; graciously given permission to use this algorithm. He says, "You can use
1922 ;;; it, if you present the following explanation of the algorithm."
1924 ;;; Algorithm (recursively presented):
1925 ;;; If x is a rational number, return x.
1926 ;;; If x = 0.0, return 0.
1927 ;;; If x < 0.0, return (- (rationalize (- x))).
1929 ;;; Call (integer-decode-float x). It returns a m,e,s=1 (mantissa,
1930 ;;; exponent, sign).
1931 ;;; If m = 0 or e >= 0: return x = m*2^e.
1932 ;;; Search a rational number between a = (m-1/2)*2^e and b = (m+1/2)*2^e
1933 ;;; with smallest possible numerator and denominator.
1934 ;;; Note 1: If m is a power of 2, we ought to take a = (m-1/4)*2^e.
1935 ;;; But in this case the result will be x itself anyway, regardless of
1936 ;;; the choice of a. Therefore we can simply ignore this case.
1937 ;;; Note 2: At first, we need to consider the closed interval [a,b].
1938 ;;; but since a and b have the denominator 2^(|e|+1) whereas x itself
1939 ;;; has a denominator <= 2^|e|, we can restrict the search to the open
1941 ;;; So, for given a and b (0 < a < b) we are searching a rational number
1942 ;;; y with a <= y <= b.
1943 ;;; Recursive algorithm fraction_between(a,b):
1944 ;;; c := (ceiling a)
1946 ;;; then return c ; because a <= c < b, c integer
1948 ;;; ; a is not integer (otherwise we would have had c = a < b)
1949 ;;; k := c-1 ; k = floor(a), k < a < b <= k+1
1950 ;;; return y = k + 1/fraction_between(1/(b-k), 1/(a-k))
1951 ;;; ; note 1 <= 1/(b-k) < 1/(a-k)
1953 ;;; You can see that we are actually computing a continued fraction expansion.
1955 ;;; Algorithm (iterative):
1956 ;;; If x is rational, return x.
1957 ;;; Call (integer-decode-float x). It returns a m,e,s (mantissa,
1958 ;;; exponent, sign).
1959 ;;; If m = 0 or e >= 0, return m*2^e*s. (This includes the case x = 0.0.)
1960 ;;; Create rational numbers a := (2*m-1)*2^(e-1) and b := (2*m+1)*2^(e-1)
1961 ;;; (positive and already in lowest terms because the denominator is a
1962 ;;; power of two and the numerator is odd).
1963 ;;; Start a continued fraction expansion
1964 ;;; p[-1] := 0, p[0] := 1, q[-1] := 1, q[0] := 0, i := 0.
1966 ;;; c := (ceiling a)
1968 ;;; then k := c-1, partial_quotient(k), (a,b) := (1/(b-k),1/(a-k)),
1970 ;;; finally partial_quotient(c).
1971 ;;; Here partial_quotient(c) denotes the iteration
1972 ;;; i := i+1, p[i] := c*p[i-1]+p[i-2], q[i] := c*q[i-1]+q[i-2].
1973 ;;; At the end, return s * (p[i]/q[i]).
1974 ;;; This rational number is already in lowest terms because
1975 ;;; p[i]*q[i-1]-p[i-1]*q[i] = (-1)^i.
1977 (defmethod rationalize ((x bigfloat
))
1978 (multiple-value-bind (frac expo sign
)
1979 (integer-decode-float x
)
1980 (cond ((or (zerop frac
) (>= expo
0))
1985 ;; expo < 0 and (2*m-1) and (2*m+1) are coprime to 2^(1-e),
1986 ;; so build the fraction up immediately, without having to do
1988 (let ((a (/ (- (* 2 frac
) 1) (ash 1 (- 1 expo
))))
1989 (b (/ (+ (* 2 frac
) 1) (ash 1 (- 1 expo
))))
1994 (do ((c (ceiling a
) (ceiling a
)))
1996 (let ((top (+ (* c p1
) p0
))
1997 (bot (+ (* c q1
) q0
)))
1998 (/ (if (minusp sign
)
2003 (p2 (+ (* k p1
) p0
))
2004 (q2 (+ (* k q1
) q0
)))
2005 (psetf a
(/ (- b k
))
2012 (defun coerce (obj type
)
2013 (flet ((coerce-error ()
2014 (error "Cannot coerce ~A to type ~S" obj type
)))
2015 (cond ((typep obj type
)
2017 ((subtypep type
'bigfloat
)
2018 ;; (coerce foo 'bigfloat). Foo has to be a real
2019 (cond ((typep obj
'real
)
2023 ((subtypep type
'complex-bigfloat
)
2024 ;; (coerce foo 'complex-bigfloat). Foo has to be a real or complex
2025 (cond ((typep obj
'real
)
2027 ((typep obj
'cl
:complex
)
2029 ((typep obj
'bigfloat
)
2033 ((typep obj
'bigfloat
)
2034 ;; (coerce bigfloat foo)
2035 (cond ((subtypep type
'cl
:float
)
2036 (float obj
(cl:coerce
0 type
)))
2037 ((subtypep type
'(cl:complex long-float
))
2038 (cl:complex
(float (realpart obj
) 1l0)
2039 (float (imagpart obj
) 1l0)))
2040 ((subtypep type
'(cl:complex double-float
))
2041 (cl:complex
(float (realpart obj
) 1d0
)
2042 (float (imagpart obj
) 1d0
)))
2043 ((subtypep type
'(cl:complex single-float
))
2044 (cl:complex
(float (realpart obj
) 1f0
)
2045 (float (imagpart obj
) 1f0
)))
2046 ((subtypep type
'cl
:complex
)
2047 ;; What should we do here? Return a
2048 ;; complex-bigfloat? A complex double-float?
2049 ;; complex single-float? I arbitrarily select
2050 ;; complex maxima:flonum for now.
2051 (cl:complex
(float (realpart obj
) 1.0)
2052 (float (imagpart obj
) 1.0)))
2055 ((typep obj
'complex-bigfloat
)
2056 ;; (coerce complex-bigfloat foo)
2057 (cond ((subtypep type
'complex-bigfloat
)
2059 ((subtypep type
'(cl:complex long-float
))
2060 (cl:complex
(float (realpart obj
) 1l0)
2061 (float (imagpart obj
) 1l0)))
2062 ((subtypep type
'(cl:complex double-float
))
2063 (cl:complex
(float (realpart obj
) 1d0
)
2064 (float (imagpart obj
) 1d0
)))
2065 ((subtypep type
'(cl:complex single-float
))
2066 (cl:complex
(float (realpart obj
) 1f0
)
2067 (float (imagpart obj
) 1f0
)))
2071 (cl:coerce obj type
)))))
2075 ;;; Return a value of pi with the same precision as the argument.
2076 ;;; For rationals, we return a single-float approximation.
2077 (defmethod %pi
((x cl
:rational
))
2078 (cl:coerce cl
:pi
'single-float
))
2080 (defmethod %pi
((x cl
:float
))
2083 (defmethod %pi
((x bigfloat
))
2084 (to (maxima::bcons
(maxima::fppi
))))
2086 (defmethod %pi
((x cl
:complex
))
2087 (cl:float cl
:pi
(realpart x
)))
2089 (defmethod %pi
((x complex-bigfloat
))
2090 (to (maxima::bcons
(maxima::fppi
))))
2094 ;;; Return a value of e with the same precision as the argument.
2095 ;;; For rationals, we return a single-float approximation.
2096 (defmethod %e
((x cl
:rational
))
2097 (cl:coerce maxima
::%e-val
'single-float
))
2099 (defmethod %e
((x cl
:float
))
2100 (cl:float maxima
::%e-val x
))
2102 (defmethod %e
((x bigfloat
))
2103 (to (maxima::bcons
(maxima::fpe
))))
2105 (defmethod %e
((x cl
:complex
))
2106 (cl:float maxima
::%e-val
(realpart x
)))
2108 (defmethod %e
((x complex-bigfloat
))
2109 (to (maxima::bcons
(maxima::fpe
))))
2111 ;;;; Useful routines
2113 ;;; Evaluation of continued fractions
2115 (defvar *debug-cf-eval
*
2117 "When true, enable some debugging prints when evaluating a
2118 continued fraction.")
2120 ;; Max number of iterations allowed when evaluating the continued
2121 ;; fraction. When this is reached, we assume that the continued
2122 ;; fraction did not converge.
2123 (defvar *max-cf-iterations
*
2125 "Max number of iterations allowed when evaluating the continued
2126 fraction. When this is reached, we assume that the continued
2127 fraction did not converge.")
2129 ;;; LENTZ - External
2131 ;;; Lentz's algorithm for evaluating continued fractions.
2133 ;;; Let the continued fraction be:
2136 ;;; b0 + ---- ---- ----
2140 ;;; Then LENTZ expects two functions, each taking a single fixnum
2141 ;;; index. The first returns the b term and the second returns the a
2142 ;;; terms as above for a give n.
2143 (defun lentz (bf af
)
2144 (let ((tiny-value-count 0))
2145 (flet ((value-or-tiny (v)
2146 ;; If v is zero, return a "tiny" number.
2149 (incf tiny-value-count
)
2151 ((or double-float cl
:complex
)
2152 (sqrt least-positive-normalized-double-float
))
2153 ((or bigfloat complex-bigfloat
)
2154 ;; What is a "tiny" bigfloat? Bigfloats have
2155 ;; unbounded exponents, so we need something
2156 ;; small, but not zero. Arbitrarily choose an
2157 ;; exponent of 50 times the precision.
2158 (expt 10 (- (* 50 maxima
::$fpprec
))))))
2160 (let* ((f (value-or-tiny (funcall bf
0)))
2165 for j from
1 upto
*max-cf-iterations
*
2166 for an
= (funcall af j
)
2167 for bn
= (funcall bf j
)
2169 (setf d
(value-or-tiny (+ bn
(* an d
))))
2170 (setf c
(value-or-tiny (+ bn
(/ an c
))))
2171 (when *debug-cf-eval
*
2172 (format t
"~&j = ~d~%" j
)
2173 (format t
" an = ~s~%" an
)
2174 (format t
" bn = ~s~%" bn
)
2175 (format t
" c = ~s~%" c
)
2176 (format t
" d = ~s~%" d
))
2177 (let ((delta (/ c d
)))
2179 (setf f
(* f delta
))
2180 (when *debug-cf-eval
*
2181 (format t
" dl= ~S (|dl - 1| = ~S)~%" delta
(abs (1- delta
)))
2182 (format t
" f = ~S~%" f
))
2183 (when (<= (abs (- delta
1)) eps
)
2184 (return-from lentz
(values f j tiny-value-count
)))))
2186 (error 'simple-error
2187 :format-control
"~<Continued fraction failed to converge after ~D iterations.~% Delta = ~S~>"
2188 :format-arguments
(list *max-cf-iterations
* (/ c d
))))))))
2190 ;;; SUM-POWER-SERIES - External
2192 ;;; SUM-POWER-SERIES sums the given power series, adding terms until
2193 ;;; the next term would not change the sum.
2195 ;;; The series to be summed is
2197 ;;; S = 1 + sum(c[k]*x^k, k, 1, inf)
2198 ;;; = 1 + sum(prod(f[n]*x, n, 1, k), k, 1, inf)
2200 ;;; where f[n] = c[n]/c[n-1].
2202 (defun sum-power-series (x f
)
2203 (let ((eps (epsilon x
)))
2205 (sum 1 (+ sum term
))
2206 (term (* x
(funcall f
1))
2207 (* term x
(funcall f k
))))
2208 ((< (abs term
) (* eps
(abs sum
)))
2211 (format t
"~4d: ~S ~S ~S~%" k sum term
(funcall f k
)))))
2213 ;; Format bigfloats using ~E format. This is suitable as a ~// format.
2215 ;; NOTE: This is a modified version of FORMAT-EXPONENTIAL from CMUCL to
2216 ;; support printing of bfloats.
2218 (defun format-e (stream number colonp atp
2220 overflowchar padchar exponentchar
)
2223 (maxima::bfloat-format-e stream
(real-value number
) colonp atp
2226 (or padchar
#\space
)
2227 (or exponentchar
#\b)))
2229 ;; FIXME: Do something better than this since this doesn't honor
2230 ;; any of the parameters.
2231 (princ number stream
))
2233 ;; We were given some other kind of object. Just use CL's normal
2234 ;; ~E printer to print it.
2236 (with-output-to-string (s)
2237 ;; Construct a suitable ~E format string from the given
2238 ;; parameters. First, handle w,d,e,k.
2239 (write-string "~V,V,V,V," s
)
2241 (format s
"'~C," overflowchar
)
2242 (write-string "," s
))
2244 (format s
"'~C," padchar
)
2245 (write-string "," s
))
2247 (format s
"'~C" exponentchar
))
2252 (write-char #\E s
))))
2253 (format stream f w d e k number
)))))
2256 (defmacro assert-equal
(expected form
)
2257 (let ((result (gensym))
2259 `(let ((,e
,expected
)
2261 (unless (equal ,e
,result
)
2262 (format *debug-io
* "Assertion failed: Expected ~S but got ~S~%" ,e
,result
)))))
2264 (assert-equal " 0.990E+00" (format nil
2265 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2266 (bigfloat:bigfloat
99/100)))
2267 (assert-equal " 0.999E+00" (format nil
2268 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2269 (bigfloat:bigfloat
999/1000)))
2270 ;; Actually " 0.100E+01", but format-e doesn't round the output.
2271 (assert-equal " 0.999E+00" (format nil
2272 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2273 (bigfloat:bigfloat
9999/10000)))
2274 (assert-equal " 0.999E-04" (format nil
2275 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2276 (bigfloat:bigfloat
0000999/10000000)))
2277 ;; Actually " 0.100E-03", but format-e doesn't round the output.
2278 (assert-equal " 0.999E-0e" (format nil
2279 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2280 (bigfloat:bigfloat
00009999/100000000)))
2281 (assert-equal " 9.999E-05" (format nil
2282 "~11,3,2,,'*,,'E/bigfloat::format-e/"
2283 (bigfloat:bigfloat
00009999/100000000)))
2284 ;; Actually " 1.000E-04", but format-e doesn't round the output.
2285 (assert-equal " 9.999E-05" (format nil
2286 "~11,3,2,,'*,,'E/bigfloat::format-e/"
2287 (bigfloat:bigfloat
000099999/1000000000)))
2288 ;; All of these currently fail.
2289 (assert-equal ".00123d+6" (format nil
2290 "~9,,,-2/bigfloat::format-e/"
2291 (bigfloat:bigfloat
1.2345689d3
)))
2292 (assert-equal "-.0012d+6" (format nil
2293 "~9,,,-2/bigfloat::format-e/"
2294 (bigfloat:bigfloat -
1.2345689d3
)))
2295 (assert-equal ".00123d+0" (format nil
2296 "~9,,,-2/bigfloat::format-e/"
2297 (bigfloat:bigfloat
1.2345689d-3
)))
2298 (assert-equal "-.0012d+0" (format nil
2299 "~9,,,-2/bigfloat::format-e/"
2300 (bigfloat:bigfloat -
1.2345689d-3
)))
2302 ;; These fail because too many digits are printed and because the
2303 ;; scale factor isn't properly applied.
2304 (assert-equal ".00000003d+8" (format nil
2306 (bigfloat:bigfloat pi
)))
2307 (assert-equal ".000003d+6" (format nil
2309 (bigfloat:bigfloat pi
)))
2310 (assert-equal "3141600.d-6" (format nil
2312 (bigfloat:bigfloat pi
)))
2313 (assert-equal " 314.16d-2" (format nil
2315 (bigfloat:bigfloat pi
)))
2316 (assert-equal " 31416.d-4" (format nil
2318 (bigfloat:bigfloat pi
)))
2319 (assert-equal " 0.3142d+1" (format nil
2321 (bigfloat:bigfloat pi
)))
2322 (assert-equal ".03142d+2" (format nil
2324 (bigfloat:bigfloat pi
)))
2325 (assert-equal "0.003141592653589793d+3" (format nil
2327 (bigfloat:bigfloat pi
)))
2328 (assert-equal "31.41592653589793d-1" (format nil
2330 (bigfloat:bigfloat pi
)))
2331 ;; Fails because exponent is printed as "b0" instead of "b+0"
2332 (assert-equal "3.141592653589793b+0" (format nil
"~E" (bigfloat:bigfloat pi
)))
2335 ;; These fail because too many digits are printed and because the
2336 ;; scale factor isn't properly applied.
2337 (assert-equal ".03142d+2" (format nil
"~9,5,,-1E" (bigfloat:bigfloat pi
)))
2338 (assert-equal " 0.03142d+2" (format nil
"~11,5,,-1E" (bigfloat:bigfloat pi
)))
2339 (assert-equal "| 3141593.d-06|" (format nil
"|~13,6,2,7E|" (bigfloat:bigfloat pi
)))
2340 (assert-equal "0.314d+01" (format nil
"~9,3,2,0,'%E" (bigfloat:bigfloat pi
)))
2341 (assert-equal "+.003d+03" (format nil
"~9,3,2,-2,'%@E" (bigfloat:bigfloat pi
)))
2342 (assert-equal "+0.003d+03" (format nil
"~10,3,2,-2,'%@E" (bigfloat:bigfloat pi
)))
2343 (assert-equal "=====+0.003d+03" (format nil
"~15,3,2,-2,'%,'=@E" (bigfloat:bigfloat pi
)))
2344 (assert-equal "0.003d+03" (format nil
"~9,3,2,-2,'%E" (bigfloat:bigfloat pi
)))
2345 (assert-equal "%%%%%%%%" (format nil
"~8,3,2,-2,'%@E" (bigfloat:bigfloat pi
)))
2348 (assert-equal "0.0f+0" (format nil
"~e" 0))
2350 ;; Fails because exponent is printed as "b0" instead of "b+0'
2351 (assert-equal "0.0b+0" (format nil
"~e" (bigfloat:bigfloat
0d0
)))
2352 ;; Fails because exponent is printed as "b0 " instead of "b+0000"
2353 (assert-equal "0.0b+0000" (format nil
"~9,,4e" (bigfloat:bigfloat
0d0
)))
2354 ;; Fails because exponent is printed as "b4" isntead of "b+4"
2355 (assert-equal "1.2345678901234567b+4" (format nil
"~E"
2356 (bigfloat:bigfloat
1.234567890123456789d4
)))
2358 ;; Fails because exponent is printed as "b36" instead of "b+36"
2359 (assert-equal "1.32922799578492b+36" (format nil
"~20E"
2360 (bigfloat:bigfloat
(expt 2d0
120))))
2361 ;; Fails because too many digits are printed and the exponent doesn't include "+".
2362 (assert-equal " 1.32922800b+36" (format nil
"~21,8E"
2363 (bigfloat:bigfloat
(expt 2d0
120))))
2367 ;; Format bigfloats using ~F format. This is suitable as a ~// format.
2369 ;; NOTE: This is a modified version of FORMAT-FIXED from CMUCL to
2370 ;; support printing of bfloats.
2372 (defun format-f (stream number colonp atp
2373 &optional w d k overflowchar padchar
)
2376 (maxima::bfloat-format-f stream
(real-value number
) colonp atp
2379 (or padchar
#\space
)))
2381 ;; FIXME: Do something better than this since this doesn't honor
2382 ;; any of the parameters.
2383 (princ number stream
))
2385 ;; We were given some other kind of object. Just use CL's normal
2386 ;; ~F printer to print it.
2388 (with-output-to-string (s)
2389 ;; Construct a suitable ~F format string from the given
2390 ;; parameters. First handle w,d,k.
2391 (write-string "~V,V,V," s
)
2393 (format s
"'~C," overflowchar
)
2394 (write-string "," s
))
2395 (if (char= padchar
#\space
)
2396 (write-string "," s
)
2397 (format s
"'~C," padchar
))
2402 (write-char #\F s
))))
2403 (format stream f w d k number
)))))
2405 ;; Format bigfloats using ~G format. This is suitable as a ~// format.
2407 ;; NOTE: This is a modified version of FORMAT-GENERAL from CMUCL to
2408 ;; support printing of bfloats.
2410 (defun format-g (stream number colonp atp
2411 &optional w d e k overflowchar padchar marker
)
2414 (maxima::bfloat-format-g stream
(real-value number
) colonp atp
2417 (or padchar
#\space
)
2420 ;; FIXME: Do something better than this since this doesn't honor
2421 ;; any of the parameters.
2422 (princ number stream
))
2424 ;; We were given some other kind of object. Just use CL's normal
2425 ;; ~G printer to print it.
2427 (with-output-to-string (s)
2428 ;; Construct a suitable ~E format string from the given
2429 ;; parameters. First, handle w,d,e,k.
2430 (write-string "~V,V,V,V," s
)
2432 (format s
"'~C," overflowchar
)
2433 (write-string "," s
))
2435 (format s
"'~C," padchar
)
2436 (write-string "," s
))
2438 (format s
"'~C" marker
))
2443 (write-char #\G s
))))
2444 (format stream f w d e k number
)))))