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::mevalp
`((maxima::%acosh maxima
::simp
)
1125 (if (maxima::bigfloatp value
)
1126 (make-instance 'bigfloat
:real value
)
1127 (make-instance 'complex-bigfloat
1128 :real
(maxima::$realpart value
)
1129 :imag
(maxima::$imagpart value
)))))
1131 ;;; Complex arguments
1133 ;;; Special functions for complex args
1135 ((frob (name &optional big-float-op-p
)
1137 (let ((big-op (intern (concatenate 'string
1138 (string '#:big-float-
)
1141 `(defmethod ,name
((a complex-bigfloat
))
1142 (let ((res (,big-op
(real-value a
)
1145 (let ((max-op (intern (concatenate 'string
"$" (string name
)) '#:maxima
)))
1146 `(defmethod ,name
((a complex-bigfloat
))
1147 ;; We should do something better than calling mevalp
1148 (let* ((arg (maxima::add
(real-value a
)
1149 (maxima::mul
'maxima
::$%i
(imag-value a
))))
1150 (result (maxima::mevalp
`((,',max-op maxima
::simp
) ,arg
))))
1165 (defmethod one-arg-atan ((a number
))
1168 (defmethod one-arg-atan ((a bigfloat
))
1169 (make-instance 'bigfloat
1170 :real
(maxima::bcons
(maxima::fpatan
(cdr (real-value a
))))))
1172 (defmethod one-arg-atan ((a complex-bigfloat
))
1173 ;; We should do something better than calling mevalp
1174 (let* ((arg (maxima::add
(real-value a
)
1175 (maxima::mul
'maxima
::$%i
(imag-value a
))))
1176 (result (maxima::mevalp
`((maxima::%atan maxima
::simp
) ,arg
))))
1177 (make-instance 'complex-bigfloat
1178 :real
(maxima::$realpart result
)
1179 :imag
(maxima::$imagpart result
))))
1181 ;; Really want type real, but gcl doesn't like that. Define methods for rational and float
1183 (defmethod two-arg-atan ((a real
) (b real
))
1188 (defmethod two-arg-atan ((a cl
:float
) (b cl
:float
))
1190 (defmethod two-arg-atan ((a cl
:rational
) (b cl
:rational
))
1192 (defmethod two-arg-atan ((a cl
:float
) (b cl
:rational
))
1194 (defmethod two-arg-atan ((a cl
:rational
) (b cl
:float
))
1198 (defmethod two-arg-atan ((a bigfloat
) (b bigfloat
))
1199 (make-instance 'bigfloat
1200 :real
(maxima::bcons
1201 (maxima::fpatan2
(cdr (real-value a
))
1202 (cdr (real-value b
))))))
1204 (defmethod two-arg-atan ((a bigfloat
) (b cl
:float
))
1205 (make-instance 'bigfloat
1206 :real
(maxima::bcons
(maxima::fpatan2
(cdr (real-value a
))
1207 (cdr (intofp b
))))))
1209 (defmethod two-arg-atan ((a bigfloat
) (b cl
:rational
))
1210 (make-instance 'bigfloat
1211 :real
(maxima::bcons
(maxima::fpatan2
(cdr (real-value a
))
1212 (cdr (intofp b
))))))
1214 (defmethod two-arg-atan ((a cl
:float
) (b bigfloat
))
1215 (make-instance 'bigfloat
1216 :real
(maxima::bcons
(maxima::fpatan2
(cdr (intofp a
))
1217 (cdr (real-value b
))))))
1219 (defmethod two-arg-atan ((a cl
:rational
) (b bigfloat
))
1220 (make-instance 'bigfloat
1221 :real
(maxima::bcons
(maxima::fpatan2
(cdr (intofp a
))
1222 (cdr (real-value b
))))))
1224 (defun atan (a &optional b
)
1229 (defmethod scale-float ((a cl
:float
) (n integer
))
1230 (cl:scale-float a n
))
1232 (defmethod scale-float ((a bigfloat
) (n integer
))
1233 (if (cl:zerop
(second (real-value a
)))
1234 (make-instance 'bigfloat
:real
(maxima::bcons
(list 0 0)))
1235 (destructuring-bind (marker mantissa exp
)
1237 (declare (ignore marker
))
1238 (make-instance 'bigfloat
:real
(maxima::bcons
(list mantissa
(+ exp n
)))))))
1242 (let ((cl-name (intern (string name
) '#:cl
)))
1243 `(defmethod ,name
((a number
))
1252 (let ((cl-name (intern (string name
) '#:cl
)))
1253 `(defmethod ,name
((a number
) &optional
(divisor 1))
1254 (,cl-name a divisor
)))))
1265 (defmethod realpart ((a bigfloat
))
1266 (make-instance 'bigfloat
:real
(real-value a
)))
1268 (defmethod realpart ((a complex-bigfloat
))
1269 (make-instance 'bigfloat
:real
(real-value a
)))
1271 (defmethod imagpart ((a bigfloat
))
1272 (make-instance 'bigfloat
:real
(intofp 0)))
1274 (defmethod imagpart ((a complex-bigfloat
))
1275 (make-instance 'bigfloat
:real
(imag-value a
)))
1277 (defmethod conjugate ((a bigfloat
))
1278 (make-instance 'bigfloat
:real
(real-value a
)))
1280 (defmethod conjugate ((a complex-bigfloat
))
1281 (make-instance 'complex-bigfloat
1282 :real
(real-value a
)
1283 :imag
(maxima::bcons
(maxima::fpminus
(cdr (imag-value a
))))))
1285 (defmethod cis ((a cl
:float
))
1288 (defmethod cis ((a cl
:rational
))
1291 (defmethod cis ((a bigfloat
))
1292 (make-instance 'complex-bigfloat
1293 :real
(maxima::bcons
(maxima::fpsin
(cdr (real-value a
)) nil
))
1294 :imag
(maxima::bcons
(maxima::fpsin
(cdr (real-value a
)) t
))))
1296 (defmethod phase ((a bigfloat
))
1297 (let ((r (cdr (real-value a
))))
1298 (if (cl:>= (car r
) 0)
1299 (make-instance 'bigfloat
:real
(maxima::bcons
(list 0 0)))
1300 (make-instance 'bigfloat
:real
(maxima::bcons
(maxima::fppi
))))))
1302 (defmethod phase ((a complex-bigfloat
))
1303 (make-instance 'bigfloat
1304 :real
(maxima::bcons
(maxima::fpatan2
(cdr (imag-value a
))
1305 (cdr (real-value a
))))))
1307 (defun max (number &rest more-numbers
)
1308 "Returns the greatest of its arguments."
1309 (declare (optimize (safety 2)) (type (or real bigfloat
) number
)
1310 #-gcl
(dynamic-extent more-numbers
))
1311 (dolist (real more-numbers
)
1312 (when (> real number
)
1313 (setq number real
)))
1316 (defun min (number &rest more-numbers
)
1317 "Returns the least of its arguments."
1318 (declare (optimize (safety 2)) (type (or real bigfloat
) number
)
1319 #-gcl
(dynamic-extent more-numbers
))
1320 (do ((nlist more-numbers
(cdr nlist
))
1321 (result (the (or real bigfloat
) number
)))
1322 ((null nlist
) (return result
))
1323 (declare (list nlist
))
1324 (if (< (car nlist
) result
)
1325 (setq result
(car nlist
)))))
1327 ;; We really want a real type, but gcl doesn't like it, so use number
1330 (defmethod one-arg-complex ((a real
))
1335 (defmethod one-arg-complex ((a cl
:float
))
1337 (defmethod one-arg-complex ((a cl
:rational
))
1341 (defmethod one-arg-complex ((a bigfloat
))
1342 (make-instance 'complex-bigfloat
1343 :real
(real-value a
)
1347 (defmethod two-arg-complex ((a real
) (b real
))
1352 (defmethod two-arg-complex ((a cl
:float
) (b cl
:float
))
1354 (defmethod two-arg-complex ((a cl
:rational
) (b cl
:rational
))
1356 (defmethod two-arg-complex ((a cl
:float
) (b cl
:rational
))
1358 (defmethod two-arg-complex ((a cl
:rational
) (b cl
:float
))
1362 (defmethod two-arg-complex ((a bigfloat
) (b bigfloat
))
1363 (make-instance 'complex-bigfloat
1364 :real
(real-value a
)
1365 :imag
(real-value b
)))
1367 (defmethod two-arg-complex ((a cl
:float
) (b bigfloat
))
1368 (make-instance 'complex-bigfloat
1370 :imag
(real-value b
)))
1372 (defmethod two-arg-complex ((a cl
:rational
) (b bigfloat
))
1373 (make-instance 'complex-bigfloat
1375 :imag
(real-value b
)))
1377 (defmethod two-arg-complex ((a bigfloat
) (b cl
:float
))
1378 (make-instance 'complex-bigfloat
1379 :real
(real-value a
)
1382 (defmethod two-arg-complex ((a bigfloat
) (b cl
:rational
))
1383 (make-instance 'complex-bigfloat
1384 :real
(real-value a
)
1387 (defun complex (a &optional b
)
1389 (two-arg-complex a b
)
1390 (one-arg-complex a
)))
1392 (defmethod unary-floor ((a bigfloat
))
1393 ;; fpentier truncates to zero, so adjust for negative numbers
1394 (let ((trunc (maxima::fpentier
(real-value a
))))
1396 ;; If the truncated value is the same as the original,
1397 ;; there's nothing to do because A was an integer.
1398 ;; Otherwise, we need to subtract 1 to make it the floor.
1405 (defmethod unary-ffloor ((a bigfloat
))
1406 ;; We can probably do better than converting to an integer and
1407 ;; converting back to a float.
1408 (make-instance 'bigfloat
:real
(intofp (unary-floor a
))))
1410 (defmethod floor ((a bigfloat
) &optional
(divisor 1))
1412 (let ((int (unary-floor a
)))
1413 (values int
(- a int
)))
1414 (let ((q (unary-floor (/ a divisor
))))
1415 (values q
(- a
(* q divisor
))))))
1417 (defmethod ffloor ((a bigfloat
) &optional
(divisor 1))
1419 (let ((int (unary-ffloor a
)))
1420 (values int
(- a int
)))
1421 (let ((q (unary-ffloor (/ a divisor
))))
1422 (values q
(- a
(* q divisor
))))))
1424 (defmethod unary-truncate ((a bigfloat
))
1425 (maxima::fpentier
(real-value a
)))
1427 (defmethod unary-ftruncate ((a bigfloat
))
1428 ;; We can probably do better than converting to an integer and
1429 ;; converting back to a float.
1430 (make-instance 'bigfloat
:real
(intofp (unary-truncate a
))))
1432 (defmethod truncate ((a bigfloat
) &optional
(divisor 1))
1434 (let ((int (unary-truncate a
)))
1435 (values int
(- a int
)))
1436 (let ((q (unary-truncate (/ a divisor
))))
1437 (values q
(- a
(* q divisor
))))))
1439 (defmethod ftruncate ((a bigfloat
) &optional
(divisor 1))
1441 (let ((int (unary-ftruncate a
)))
1442 (values int
(- a int
)))
1443 (let ((q (unary-ftruncate (/ a divisor
))))
1444 (values q
(- a
(* q divisor
))))))
1446 (defmethod unary-ceiling ((a bigfloat
))
1447 ;; fpentier truncates to zero, so adjust for positive numbers.
1449 (maxima::fpentier
(real-value a
))
1450 (maxima::fpentier
(real-value (+ a
1)))))
1452 (defmethod unary-fceiling ((a bigfloat
))
1453 ;; We can probably do better than converting to an integer and
1454 ;; converting back to a float.
1455 (make-instance 'bigfloat
:real
(intofp (unary-ceiling a
))))
1457 (defmethod ceiling ((a bigfloat
) &optional
(divisor 1))
1459 (let ((int (unary-ceiling a
)))
1460 (values int
(- a int
)))
1461 (let ((q (unary-ceiling (/ a divisor
))))
1462 (values q
(- a
(* q divisor
))))))
1464 (defmethod fceiling ((a bigfloat
) &optional
(divisor 1))
1466 (let ((int (unary-fceiling a
)))
1467 (values int
(- a int
)))
1468 (let ((q (unary-fceiling (/ a divisor
))))
1469 (values q
(- a
(* q divisor
))))))
1471 ;; Stolen from CMUCL.
1472 (defmethod round ((a bigfloat
) &optional
(divisor 1))
1473 (multiple-value-bind (tru rem
)
1474 (truncate a divisor
)
1477 (let ((thresh (/ (abs divisor
) 2)))
1478 (cond ((or (> rem thresh
)
1479 (and (= rem thresh
) (oddp tru
)))
1480 (if (minusp divisor
)
1481 (values (- tru
1) (+ rem divisor
))
1482 (values (+ tru
1) (- rem divisor
))))
1483 ((let ((-thresh (- thresh
)))
1485 (and (= rem -thresh
) (oddp tru
))))
1486 (if (minusp divisor
)
1487 (values (+ tru
1) (- rem divisor
))
1488 (values (- tru
1) (+ rem divisor
))))
1489 (t (values tru rem
)))))))
1491 (defmethod fround ((number bigfloat
) &optional
(divisor 1))
1492 "Same as ROUND, but returns first value as a float."
1493 (multiple-value-bind (res rem
)
1494 (round number divisor
)
1495 (values (bigfloat res
) rem
)))
1497 (defmethod expt ((a number
) (b number
))
1500 ;; This needs more work
1501 (defmethod expt ((a numeric
) (b numeric
))
1503 ;; CLHS says if the power is 0, the answer is 1 of the appropriate type.
1504 (if (or (typep a
'complex-bigfloat
)
1505 (typep b
'complex-bigfloat
))
1506 (complex (bigfloat 1))
1508 (cond ((and (zerop a
) (plusp (realpart b
)))
1510 ((and (realp b
) (= b
(truncate b
)))
1511 ;; Use the numeric^number method because it can be much
1512 ;; more accurate when b is an integer.
1513 (expt a
(truncate b
)))
1515 (with-extra-precision ((expt-extra-bits a b
)
1517 (exp (* b
(log a
))))))))
1519 (defmethod expt ((a cl
:number
) (b numeric
))
1521 ;; CLHS says if the power is 0, the answer is 1 of the appropriate type.
1522 (if (or (typep a
'cl
:complex
)
1523 (typep b
'complex-bigfloat
))
1524 (complex (bigfloat 1))
1526 (cond ((and (zerop a
) (plusp (realpart b
)))
1528 ((and (realp b
) (= b
(truncate b
)))
1529 (with-extra-precision ((expt-extra-bits a b
)
1531 (intofp (expt a
(truncate b
)))))
1533 (with-extra-precision ((expt-extra-bits a b
)
1535 (exp (* b
(log (bigfloat a
)))))))))
1537 (defmethod expt ((a numeric
) (b cl
:number
))
1539 ;; CLHS says if the power is 0, the answer is 1 of the appropriate type.
1540 (if (or (typep a
'complex-bigfloat
)
1541 (typep b
'cl
:complex
))
1542 (complex (bigfloat 1))
1544 (if (and (zerop a
) (plusp (realpart b
)))
1546 ;; Handle a few special cases using multiplication.
1556 ((= b -
3) (/ (* a a a
)))
1564 (with-extra-precision ((expt-extra-bits a b
)
1566 (exp (* (bigfloat b
) (log a
)))))))))
1568 ;; Handle a^b a little more carefully because the result is known to
1569 ;; be real when a is real and b is an integer.
1570 (defmethod expt ((a bigfloat
) (b integer
))
1573 ((and (zerop a
) (plusp b
))
1574 ;; 0^b, for positive b
1576 ;; Handle a few special cases using multiplication.
1580 ((eql b -
2) (/ (* a a
)))
1581 ((eql b
3) (* a a a
))
1582 ((eql b -
3) (/ (* a a a
)))
1590 ;; a^b = exp(b*log(|a|) + %i*%pi*b)
1591 ;; = exp(b*log(|a|))*exp(%i*%pi*b)
1592 ;; = (-1)^b*exp(b*log(|a|))
1593 (with-extra-precision ((expt-extra-bits a b
)
1595 (* (exp (* b
(log (abs a
))))
1596 (if (oddp b
) -
1 1))))
1598 (with-extra-precision ((expt-extra-bits a b
)
1600 (exp (* b
(log a
)))))))
1604 ;;; TO takes a maxima number and converts it. Floats remain
1605 ;;; floats, maxima cl:rationals are converted to CL cl:rationals. Maxima
1606 ;;; bigfloats are convert to BIGFLOATS. Maxima complex numbers are
1607 ;;; converted to CL complex numbers or to COMPLEX-BIGFLOAT's.
1608 (defun to (maxima-num &optional imag
)
1609 (let ((result (ignore-errors (%to maxima-num imag
))))
1611 (maxima::merror
(intl:gettext
"BIGFLOAT: unable to convert ~M to a CL or BIGFLOAT number.")
1613 (maxima::add maxima-num
(maxima::mul imag
'maxima
::$%i
))
1616 ;;; MAYBE-TO - External
1618 ;;; Like TO, but if the maxima number can't be converted to a CL
1619 ;;; number or BIGFLOAT, just return the maxima number.
1620 (defun maybe-to (maxima-num &optional imag
)
1621 (let ((result (ignore-errors (%to maxima-num imag
))))
1624 (maxima::add maxima-num imag
)
1627 (defun %to
(maxima-num &optional imag
)
1629 ;; Clisp has a "feature" that (complex rat float) does not
1630 ;; make the both components of the complex number a float.
1631 ;; Sometimes this is nice, but other times it's annoying
1632 ;; because it is non-ANSI behavior. For our code, we really
1633 ;; want both components to be a float.
1635 (complex (to maxima-num
) (to imag
))
1637 (let ((re (to maxima-num
))
1639 (cond ((and (rationalp re
) (floatp im
))
1640 (setf re
(float re im
)))
1641 ((and (rational im
) (floatp re
))
1642 (setf im
(float im re
))))
1645 (cond ((cl:numberp maxima-num
)
1647 ((eq maxima-num
'maxima
::$%i
)
1648 ;; Convert %i to an exact complex cl:rational.
1651 ;; Some kind of maxima number
1652 (cond ((maxima::ratnump maxima-num
)
1653 ;; Maxima cl:rational ((mrat ...) num den)
1654 (/ (second maxima-num
) (third maxima-num
)))
1655 ((maxima::$bfloatp maxima-num
)
1656 (bigfloat maxima-num
))
1657 ((maxima::complex-number-p maxima-num
#'(lambda (x)
1659 (maxima::$bfloatp x
)
1661 (eq (caar x
) 'maxima
::rat
)))))
1662 ;; We have some kind of complex number whose
1663 ;; parts are a cl:real, a bfloat, or a Maxima
1665 (let ((re (maxima::$realpart maxima-num
))
1666 (im (maxima::$imagpart maxima-num
)))
1668 ((or (typep maxima-num
'bigfloat
)
1669 (typep maxima-num
'complex-bigfloat
))
1672 (error "BIGFLOAT: unable to convert to a CL or BIGFLOAT number."))))))
1674 ;;; EPSILON - External
1676 ;;; Return the float epsilon value for the given float type.
1677 (defmethod epsilon ((x cl
:float
))
1679 (short-float short-float-epsilon
)
1680 (single-float single-float-epsilon
)
1681 (double-float double-float-epsilon
)
1682 (long-float long-float-epsilon
)))
1684 (defmethod epsilon ((x cl
:complex
))
1685 (epsilon (cl:realpart x
)))
1687 (defmethod epsilon ((x bigfloat
))
1688 ;; epsilon is just above 2^(-fpprec).
1689 (make-instance 'bigfloat
1690 :real
(maxima::bcons
(list (1+ (ash 1 (1- maxima
::fpprec
)))
1691 (- (1- maxima
::fpprec
))))))
1693 (defmethod epsilon ((x complex-bigfloat
))
1694 (epsilon (realpart x
)))
1698 ;; Compiler macros to convert + to multiple calls to two-arg-+. Same
1700 (define-compiler-macro + (&whole form
&rest args
)
1701 (declare (ignore form
))
1704 (do ((args (cdr args
) (cdr args
))
1706 `(two-arg-+ ,res
,(car args
))))
1707 ((null args
) res
))))
1709 (define-compiler-macro -
(&whole form number
&rest more-numbers
)
1710 (declare (ignore form
))
1712 (do ((nlist more-numbers
(cdr nlist
))
1714 ((atom nlist
) result
)
1715 (declare (list nlist
))
1716 (setq result
`(two-arg-- ,result
,(car nlist
))))
1717 `(unary-minus ,number
)))
1719 (define-compiler-macro * (&whole form
&rest args
)
1720 (declare (ignore form
))
1723 (do ((args (cdr args
) (cdr args
))
1725 `(two-arg-* ,res
,(car args
))))
1726 ((null args
) res
))))
1728 (define-compiler-macro / (number &rest more-numbers
)
1730 (do ((nlist more-numbers
(cdr nlist
))
1732 ((atom nlist
) result
)
1733 (declare (list nlist
))
1734 (setq result
`(two-arg-/ ,result
,(car nlist
))))
1735 `(unary-divide ,number
)))
1737 (define-compiler-macro /= (&whole form number
&rest more-numbers
)
1738 ;; Convert (/= x y) to (not (two-arg-= x y)). Should we try to
1739 ;; handle a few more cases?
1740 (if (cdr more-numbers
)
1742 `(not (two-arg-= ,number
,(car more-numbers
)))))
1744 ;; Compiler macros to convert <, >, <=, and >= into multiple calls of
1745 ;; the corresponding two-arg-<foo> function.
1748 (let ((method (intern (concatenate 'string
1749 (string '#:two-arg-
)
1750 (symbol-name op
)))))
1751 `(define-compiler-macro ,op
(number &rest more-numbers
)
1752 (do* ((n number
(car nlist
))
1753 (nlist more-numbers
(cdr nlist
))
1756 `(and ,@(nreverse res
)))
1757 (push `(,',method
,n
,(car nlist
)) res
))))))
1763 (defmethod integer-decode-float ((x cl
:float
))
1764 (cl:integer-decode-float x
))
1766 (defmethod integer-decode-float ((x bigfloat
))
1767 (let ((r (real-value x
)))
1768 (values (abs (second r
))
1769 (- (third r
) (third (first r
)))
1770 (signum (second r
)))))
1772 (defmethod decode-float ((x cl
:float
))
1773 (cl:decode-float x
))
1775 (defmethod decode-float ((x bigfloat
))
1776 (let ((r (real-value x
)))
1777 (values (make-instance 'bigfloat
1778 :real
(maxima::bcons
(list (abs (second r
)) 0)))
1780 (bigfloat (signum (second r
))))))
1782 ;; GCL doesn't have a REAL class!
1785 (defmethod float ((x cl
:float
) (y cl
:float
))
1788 (defmethod float ((x cl
:rational
) (y cl
:float
))
1791 (defmethod float ((x cl
:float
) (y bigfloat
))
1794 (defmethod float ((x cl
:rational
) (y bigfloat
))
1800 (defmethod float ((x real
) (y cl
:float
))
1803 (defmethod float ((x real
) (y bigfloat
))
1807 ;; Like Maxima's fp2flo, but for single-float numbers.
1808 (defun fp2single (l)
1809 (let ((precision (caddar l
))
1811 (exponent (caddr l
))
1812 (fpprec (float-digits 1f0
))
1814 ;; Round the mantissa to the number of bits of precision of the
1815 ;; machine, and then convert it to a floating point fraction. We
1816 ;; have 0.5 <= mantissa < 1
1817 (setq mantissa
(maxima::quotient
(maxima::fpround mantissa
)
1819 ;; Multiply the mantissa by the exponent portion. I'm not sure
1820 ;; why the exponent computation is so complicated.
1822 ;; GCL doesn't signal overflow from scale-float if the number
1823 ;; would overflow. We have to do it this way. 0.5 <= mantissa <
1824 ;; 1. The largest double-float is .999999 * 2^128. So if the
1825 ;; exponent is 128 or higher, we have an overflow.
1826 (let ((e (+ exponent
(- precision
) maxima
::*m fpprec
)))
1827 (if (>= (abs e
) 129)
1828 (maxima::merror
(intl:gettext
"FP2SINGLE: floating point overflow converting ~:M to float.") l
)
1829 (cl:scale-float mantissa e
)))))
1832 (defmethod float ((x bigfloat
) (y cl
:float
))
1833 (if (typep y
'maxima
::flonum
)
1834 (maxima::fp2flo
(real-value x
))
1835 (fp2single (real-value x
))))
1837 (defmethod random ((x cl
:float
) &optional
(state cl
:*random-state
*))
1838 (cl:random x state
))
1839 (defmethod random ((x integer
) &optional
(state cl
:*random-state
*))
1840 (cl:random x state
))
1842 (defmethod random ((x bigfloat
) &optional
(state cl
:*random-state
*))
1843 ;; Generate an integer with fpprec bits, and convert to a bigfloat
1844 ;; by making the exponent 0. Then multiply by the arg to get the
1847 (let ((int (cl:random
(ash 1 maxima
::fpprec
) state
)))
1848 (* x
(bigfloat (maxima::bcons
(list int
0)))))
1849 (error "Argument is not a positive bigfloat: ~A~%" x
)))
1851 (defmethod signum ((x number
))
1854 (defmethod signum ((x bigfloat
))
1862 (defmethod signum ((x complex-bigfloat
))
1865 (defmethod float-sign ((x cl
:float
))
1868 (defmethod float-sign ((x bigfloat
))
1873 (defmethod float-digits ((x cl
:float
))
1874 (cl:float-digits x
))
1876 (defmethod float-digits ((x bigfloat
))
1877 ;; Should we just return fpprec or should we get the actual number
1878 ;; of bits in the bigfloat number? We choose the latter in case the
1879 ;; number and fpprec don't match.
1880 (let ((r (slot-value x
'real
)))
1884 (defmethod rational ((x real
))
1889 (defmethod rational ((x cl
:float
))
1891 (defmethod rational ((x cl
:rational
))
1895 (defmethod rational ((x bigfloat
))
1896 (destructuring-bind ((marker simp prec
) mantissa exp
)
1898 (declare (ignore marker simp
))
1899 (* mantissa
(expt 2 (- exp prec
)))))
1902 (defmethod rationalize ((x real
))
1907 (defmethod rationalize ((x cl
:float
))
1909 (defmethod rationalize ((x cl
:rational
))
1914 ;;; This routine taken from CMUCL, which, in turn is a routine from
1915 ;;; CLISP, which is GPL.
1917 ;;; I (rtoy) have modified it from CMUCL so that it only handles bigfloats.
1919 ;;; RATIONALIZE -- Public
1921 ;;; The algorithm here is the method described in CLISP. Bruno Haible has
1922 ;;; graciously given permission to use this algorithm. He says, "You can use
1923 ;;; it, if you present the following explanation of the algorithm."
1925 ;;; Algorithm (recursively presented):
1926 ;;; If x is a rational number, return x.
1927 ;;; If x = 0.0, return 0.
1928 ;;; If x < 0.0, return (- (rationalize (- x))).
1930 ;;; Call (integer-decode-float x). It returns a m,e,s=1 (mantissa,
1931 ;;; exponent, sign).
1932 ;;; If m = 0 or e >= 0: return x = m*2^e.
1933 ;;; Search a rational number between a = (m-1/2)*2^e and b = (m+1/2)*2^e
1934 ;;; with smallest possible numerator and denominator.
1935 ;;; Note 1: If m is a power of 2, we ought to take a = (m-1/4)*2^e.
1936 ;;; But in this case the result will be x itself anyway, regardless of
1937 ;;; the choice of a. Therefore we can simply ignore this case.
1938 ;;; Note 2: At first, we need to consider the closed interval [a,b].
1939 ;;; but since a and b have the denominator 2^(|e|+1) whereas x itself
1940 ;;; has a denominator <= 2^|e|, we can restrict the search to the open
1942 ;;; So, for given a and b (0 < a < b) we are searching a rational number
1943 ;;; y with a <= y <= b.
1944 ;;; Recursive algorithm fraction_between(a,b):
1945 ;;; c := (ceiling a)
1947 ;;; then return c ; because a <= c < b, c integer
1949 ;;; ; a is not integer (otherwise we would have had c = a < b)
1950 ;;; k := c-1 ; k = floor(a), k < a < b <= k+1
1951 ;;; return y = k + 1/fraction_between(1/(b-k), 1/(a-k))
1952 ;;; ; note 1 <= 1/(b-k) < 1/(a-k)
1954 ;;; You can see that we are actually computing a continued fraction expansion.
1956 ;;; Algorithm (iterative):
1957 ;;; If x is rational, return x.
1958 ;;; Call (integer-decode-float x). It returns a m,e,s (mantissa,
1959 ;;; exponent, sign).
1960 ;;; If m = 0 or e >= 0, return m*2^e*s. (This includes the case x = 0.0.)
1961 ;;; Create rational numbers a := (2*m-1)*2^(e-1) and b := (2*m+1)*2^(e-1)
1962 ;;; (positive and already in lowest terms because the denominator is a
1963 ;;; power of two and the numerator is odd).
1964 ;;; Start a continued fraction expansion
1965 ;;; p[-1] := 0, p[0] := 1, q[-1] := 1, q[0] := 0, i := 0.
1967 ;;; c := (ceiling a)
1969 ;;; then k := c-1, partial_quotient(k), (a,b) := (1/(b-k),1/(a-k)),
1971 ;;; finally partial_quotient(c).
1972 ;;; Here partial_quotient(c) denotes the iteration
1973 ;;; i := i+1, p[i] := c*p[i-1]+p[i-2], q[i] := c*q[i-1]+q[i-2].
1974 ;;; At the end, return s * (p[i]/q[i]).
1975 ;;; This rational number is already in lowest terms because
1976 ;;; p[i]*q[i-1]-p[i-1]*q[i] = (-1)^i.
1978 (defmethod rationalize ((x bigfloat
))
1979 (multiple-value-bind (frac expo sign
)
1980 (integer-decode-float x
)
1981 (cond ((or (zerop frac
) (>= expo
0))
1986 ;; expo < 0 and (2*m-1) and (2*m+1) are coprime to 2^(1-e),
1987 ;; so build the fraction up immediately, without having to do
1989 (let ((a (/ (- (* 2 frac
) 1) (ash 1 (- 1 expo
))))
1990 (b (/ (+ (* 2 frac
) 1) (ash 1 (- 1 expo
))))
1995 (do ((c (ceiling a
) (ceiling a
)))
1997 (let ((top (+ (* c p1
) p0
))
1998 (bot (+ (* c q1
) q0
)))
1999 (/ (if (minusp sign
)
2004 (p2 (+ (* k p1
) p0
))
2005 (q2 (+ (* k q1
) q0
)))
2006 (psetf a
(/ (- b k
))
2013 (defun coerce (obj type
)
2014 (flet ((coerce-error ()
2015 (error "Cannot coerce ~A to type ~S" obj type
)))
2016 (cond ((typep obj type
)
2018 ((subtypep type
'bigfloat
)
2019 ;; (coerce foo 'bigfloat). Foo has to be a real
2020 (cond ((typep obj
'real
)
2024 ((subtypep type
'complex-bigfloat
)
2025 ;; (coerce foo 'complex-bigfloat). Foo has to be a real or complex
2026 (cond ((typep obj
'real
)
2028 ((typep obj
'cl
:complex
)
2030 ((typep obj
'bigfloat
)
2034 ((typep obj
'bigfloat
)
2035 ;; (coerce bigfloat foo)
2036 (cond ((subtypep type
'cl
:float
)
2037 (float obj
(cl:coerce
0 type
)))
2038 ((subtypep type
'(cl:complex long-float
))
2039 (cl:complex
(float (realpart obj
) 1l0)
2040 (float (imagpart obj
) 1l0)))
2041 ((subtypep type
'(cl:complex double-float
))
2042 (cl:complex
(float (realpart obj
) 1d0
)
2043 (float (imagpart obj
) 1d0
)))
2044 ((subtypep type
'(cl:complex single-float
))
2045 (cl:complex
(float (realpart obj
) 1f0
)
2046 (float (imagpart obj
) 1f0
)))
2047 ((subtypep type
'cl
:complex
)
2048 ;; What should we do here? Return a
2049 ;; complex-bigfloat? A complex double-float?
2050 ;; complex single-float? I arbitrarily select
2051 ;; complex maxima:flonum for now.
2052 (cl:complex
(float (realpart obj
) 1.0)
2053 (float (imagpart obj
) 1.0)))
2056 ((typep obj
'complex-bigfloat
)
2057 ;; (coerce complex-bigfloat foo)
2058 (cond ((subtypep type
'complex-bigfloat
)
2060 ((subtypep type
'(cl:complex long-float
))
2061 (cl:complex
(float (realpart obj
) 1l0)
2062 (float (imagpart obj
) 1l0)))
2063 ((subtypep type
'(cl:complex double-float
))
2064 (cl:complex
(float (realpart obj
) 1d0
)
2065 (float (imagpart obj
) 1d0
)))
2066 ((subtypep type
'(cl:complex single-float
))
2067 (cl:complex
(float (realpart obj
) 1f0
)
2068 (float (imagpart obj
) 1f0
)))
2072 (cl:coerce obj type
)))))
2076 ;;; Return a value of pi with the same precision as the argument.
2077 ;;; For rationals, we return a single-float approximation.
2078 (defmethod %pi
((x cl
:rational
))
2079 (cl:coerce cl
:pi
'single-float
))
2081 (defmethod %pi
((x cl
:float
))
2084 (defmethod %pi
((x bigfloat
))
2085 (to (maxima::bcons
(maxima::fppi
))))
2087 (defmethod %pi
((x cl
:complex
))
2088 (cl:float cl
:pi
(realpart x
)))
2090 (defmethod %pi
((x complex-bigfloat
))
2091 (to (maxima::bcons
(maxima::fppi
))))
2095 ;;; Return a value of e with the same precision as the argument.
2096 ;;; For rationals, we return a single-float approximation.
2097 (defmethod %e
((x cl
:rational
))
2098 (cl:coerce maxima
::%e-val
'single-float
))
2100 (defmethod %e
((x cl
:float
))
2101 (cl:float maxima
::%e-val x
))
2103 (defmethod %e
((x bigfloat
))
2104 (to (maxima::bcons
(maxima::fpe
))))
2106 (defmethod %e
((x cl
:complex
))
2107 (cl:float maxima
::%e-val
(realpart x
)))
2109 (defmethod %e
((x complex-bigfloat
))
2110 (to (maxima::bcons
(maxima::fpe
))))
2112 ;;;; Useful routines
2114 ;;; Evaluation of continued fractions
2116 (defvar *debug-cf-eval
*
2118 "When true, enable some debugging prints when evaluating a
2119 continued fraction.")
2121 ;; Max number of iterations allowed when evaluating the continued
2122 ;; fraction. When this is reached, we assume that the continued
2123 ;; fraction did not converge.
2124 (defvar *max-cf-iterations
*
2126 "Max number of iterations allowed when evaluating the continued
2127 fraction. When this is reached, we assume that the continued
2128 fraction did not converge.")
2130 ;;; LENTZ - External
2132 ;;; Lentz's algorithm for evaluating continued fractions.
2134 ;;; Let the continued fraction be:
2137 ;;; b0 + ---- ---- ----
2141 ;;; Then LENTZ expects two functions, each taking a single fixnum
2142 ;;; index. The first returns the b term and the second returns the a
2143 ;;; terms as above for a give n.
2144 (defun lentz (bf af
)
2145 (let ((tiny-value-count 0))
2146 (flet ((value-or-tiny (v)
2147 ;; If v is zero, return a "tiny" number.
2150 (incf tiny-value-count
)
2152 ((or double-float cl
:complex
)
2153 (sqrt least-positive-normalized-double-float
))
2154 ((or bigfloat complex-bigfloat
)
2155 ;; What is a "tiny" bigfloat? Bigfloats have
2156 ;; unbounded exponents, so we need something
2157 ;; small, but not zero. Arbitrarily choose an
2158 ;; exponent of 50 times the precision.
2159 (expt 10 (- (* 50 maxima
::$fpprec
))))))
2161 (let* ((f (value-or-tiny (funcall bf
0)))
2166 for j from
1 upto
*max-cf-iterations
*
2167 for an
= (funcall af j
)
2168 for bn
= (funcall bf j
)
2170 (setf d
(value-or-tiny (+ bn
(* an d
))))
2171 (setf c
(value-or-tiny (+ bn
(/ an c
))))
2172 (when *debug-cf-eval
*
2173 (format t
"~&j = ~d~%" j
)
2174 (format t
" an = ~s~%" an
)
2175 (format t
" bn = ~s~%" bn
)
2176 (format t
" c = ~s~%" c
)
2177 (format t
" d = ~s~%" d
))
2178 (let ((delta (/ c d
)))
2180 (setf f
(* f delta
))
2181 (when *debug-cf-eval
*
2182 (format t
" dl= ~S (|dl - 1| = ~S)~%" delta
(abs (1- delta
)))
2183 (format t
" f = ~S~%" f
))
2184 (when (<= (abs (- delta
1)) eps
)
2185 (return-from lentz
(values f j tiny-value-count
)))))
2187 (error 'simple-error
2188 :format-control
"~<Continued fraction failed to converge after ~D iterations.~% Delta = ~S~>"
2189 :format-arguments
(list *max-cf-iterations
* (/ c d
))))))))
2191 ;;; SUM-POWER-SERIES - External
2193 ;;; SUM-POWER-SERIES sums the given power series, adding terms until
2194 ;;; the next term would not change the sum.
2196 ;;; The series to be summed is
2198 ;;; S = 1 + sum(c[k]*x^k, k, 1, inf)
2199 ;;; = 1 + sum(prod(f[n]*x, n, 1, k), k, 1, inf)
2201 ;;; where f[n] = c[n]/c[n-1].
2203 (defun sum-power-series (x f
)
2204 (let ((eps (epsilon x
)))
2206 (sum 1 (+ sum term
))
2207 (term (* x
(funcall f
1))
2208 (* term x
(funcall f k
))))
2209 ((< (abs term
) (* eps
(abs sum
)))
2212 (format t
"~4d: ~S ~S ~S~%" k sum term
(funcall f k
)))))
2214 ;; Format bigfloats using ~E format. This is suitable as a ~// format.
2216 ;; NOTE: This is a modified version of FORMAT-EXPONENTIAL from CMUCL to
2217 ;; support printing of bfloats.
2219 (defun format-e (stream number colonp atp
2221 overflowchar padchar exponentchar
)
2224 (maxima::bfloat-format-e stream
(real-value number
) colonp atp
2227 (or padchar
#\space
)
2228 (or exponentchar
#\b)))
2230 ;; FIXME: Do something better than this since this doesn't honor
2231 ;; any of the parameters.
2232 (princ number stream
))
2234 ;; We were given some other kind of object. Just use CL's normal
2235 ;; ~E printer to print it.
2237 (with-output-to-string (s)
2238 ;; Construct a suitable ~E format string from the given
2239 ;; parameters. First, handle w,d,e,k.
2240 (write-string "~V,V,V,V," s
)
2242 (format s
"'~C," overflowchar
)
2243 (write-string "," s
))
2245 (format s
"'~C," padchar
)
2246 (write-string "," s
))
2248 (format s
"'~C" exponentchar
))
2253 (write-char #\E s
))))
2254 (format stream f w d e k number
)))))
2257 (defmacro assert-equal
(expected form
)
2258 (let ((result (gensym))
2260 `(let ((,e
,expected
)
2262 (unless (equal ,e
,result
)
2263 (format *debug-io
* "Assertion failed: Expected ~S but got ~S~%" ,e
,result
)))))
2265 (assert-equal " 0.990E+00" (format nil
2266 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2267 (bigfloat:bigfloat
99/100)))
2268 (assert-equal " 0.999E+00" (format nil
2269 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2270 (bigfloat:bigfloat
999/1000)))
2271 ;; Actually " 0.100E+01", but format-e doesn't round the output.
2272 (assert-equal " 0.999E+00" (format nil
2273 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2274 (bigfloat:bigfloat
9999/10000)))
2275 (assert-equal " 0.999E-04" (format nil
2276 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2277 (bigfloat:bigfloat
0000999/10000000)))
2278 ;; Actually " 0.100E-03", but format-e doesn't round the output.
2279 (assert-equal " 0.999E-0e" (format nil
2280 "~11,3,2,0,'*,,'E/bigfloat::format-e/"
2281 (bigfloat:bigfloat
00009999/100000000)))
2282 (assert-equal " 9.999E-05" (format nil
2283 "~11,3,2,,'*,,'E/bigfloat::format-e/"
2284 (bigfloat:bigfloat
00009999/100000000)))
2285 ;; Actually " 1.000E-04", but format-e doesn't round the output.
2286 (assert-equal " 9.999E-05" (format nil
2287 "~11,3,2,,'*,,'E/bigfloat::format-e/"
2288 (bigfloat:bigfloat
000099999/1000000000)))
2289 ;; All of these currently fail.
2290 (assert-equal ".00123d+6" (format nil
2291 "~9,,,-2/bigfloat::format-e/"
2292 (bigfloat:bigfloat
1.2345689d3
)))
2293 (assert-equal "-.0012d+6" (format nil
2294 "~9,,,-2/bigfloat::format-e/"
2295 (bigfloat:bigfloat -
1.2345689d3
)))
2296 (assert-equal ".00123d+0" (format nil
2297 "~9,,,-2/bigfloat::format-e/"
2298 (bigfloat:bigfloat
1.2345689d-3
)))
2299 (assert-equal "-.0012d+0" (format nil
2300 "~9,,,-2/bigfloat::format-e/"
2301 (bigfloat:bigfloat -
1.2345689d-3
)))
2303 ;; These fail because too many digits are printed and because the
2304 ;; scale factor isn't properly applied.
2305 (assert-equal ".00000003d+8" (format nil
2307 (bigfloat:bigfloat pi
)))
2308 (assert-equal ".000003d+6" (format nil
2310 (bigfloat:bigfloat pi
)))
2311 (assert-equal "3141600.d-6" (format nil
2313 (bigfloat:bigfloat pi
)))
2314 (assert-equal " 314.16d-2" (format nil
2316 (bigfloat:bigfloat pi
)))
2317 (assert-equal " 31416.d-4" (format nil
2319 (bigfloat:bigfloat pi
)))
2320 (assert-equal " 0.3142d+1" (format nil
2322 (bigfloat:bigfloat pi
)))
2323 (assert-equal ".03142d+2" (format nil
2325 (bigfloat:bigfloat pi
)))
2326 (assert-equal "0.003141592653589793d+3" (format nil
2328 (bigfloat:bigfloat pi
)))
2329 (assert-equal "31.41592653589793d-1" (format nil
2331 (bigfloat:bigfloat pi
)))
2332 ;; Fails because exponent is printed as "b0" instead of "b+0"
2333 (assert-equal "3.141592653589793b+0" (format nil
"~E" (bigfloat:bigfloat pi
)))
2336 ;; These fail because too many digits are printed and because the
2337 ;; scale factor isn't properly applied.
2338 (assert-equal ".03142d+2" (format nil
"~9,5,,-1E" (bigfloat:bigfloat pi
)))
2339 (assert-equal " 0.03142d+2" (format nil
"~11,5,,-1E" (bigfloat:bigfloat pi
)))
2340 (assert-equal "| 3141593.d-06|" (format nil
"|~13,6,2,7E|" (bigfloat:bigfloat pi
)))
2341 (assert-equal "0.314d+01" (format nil
"~9,3,2,0,'%E" (bigfloat:bigfloat pi
)))
2342 (assert-equal "+.003d+03" (format nil
"~9,3,2,-2,'%@E" (bigfloat:bigfloat pi
)))
2343 (assert-equal "+0.003d+03" (format nil
"~10,3,2,-2,'%@E" (bigfloat:bigfloat pi
)))
2344 (assert-equal "=====+0.003d+03" (format nil
"~15,3,2,-2,'%,'=@E" (bigfloat:bigfloat pi
)))
2345 (assert-equal "0.003d+03" (format nil
"~9,3,2,-2,'%E" (bigfloat:bigfloat pi
)))
2346 (assert-equal "%%%%%%%%" (format nil
"~8,3,2,-2,'%@E" (bigfloat:bigfloat pi
)))
2349 (assert-equal "0.0f+0" (format nil
"~e" 0))
2351 ;; Fails because exponent is printed as "b0" instead of "b+0'
2352 (assert-equal "0.0b+0" (format nil
"~e" (bigfloat:bigfloat
0d0
)))
2353 ;; Fails because exponent is printed as "b0 " instead of "b+0000"
2354 (assert-equal "0.0b+0000" (format nil
"~9,,4e" (bigfloat:bigfloat
0d0
)))
2355 ;; Fails because exponent is printed as "b4" isntead of "b+4"
2356 (assert-equal "1.2345678901234567b+4" (format nil
"~E"
2357 (bigfloat:bigfloat
1.234567890123456789d4
)))
2359 ;; Fails because exponent is printed as "b36" instead of "b+36"
2360 (assert-equal "1.32922799578492b+36" (format nil
"~20E"
2361 (bigfloat:bigfloat
(expt 2d0
120))))
2362 ;; Fails because too many digits are printed and the exponent doesn't include "+".
2363 (assert-equal " 1.32922800b+36" (format nil
"~21,8E"
2364 (bigfloat:bigfloat
(expt 2d0
120))))
2368 ;; Format bigfloats using ~F format. This is suitable as a ~// format.
2370 ;; NOTE: This is a modified version of FORMAT-FIXED from CMUCL to
2371 ;; support printing of bfloats.
2373 (defun format-f (stream number colonp atp
2374 &optional w d k overflowchar padchar
)
2377 (maxima::bfloat-format-f stream
(real-value number
) colonp atp
2380 (or padchar
#\space
)))
2382 ;; FIXME: Do something better than this since this doesn't honor
2383 ;; any of the parameters.
2384 (princ number stream
))
2386 ;; We were given some other kind of object. Just use CL's normal
2387 ;; ~F printer to print it.
2389 (with-output-to-string (s)
2390 ;; Construct a suitable ~F format string from the given
2391 ;; parameters. First handle w,d,k.
2392 (write-string "~V,V,V," s
)
2394 (format s
"'~C," overflowchar
)
2395 (write-string "," s
))
2396 (if (char= padchar
#\space
)
2397 (write-string "," s
)
2398 (format s
"'~C," padchar
))
2403 (write-char #\F s
))))
2404 (format stream f w d k number
)))))
2406 ;; Format bigfloats using ~G format. This is suitable as a ~// format.
2408 ;; NOTE: This is a modified version of FORMAT-GENERAL from CMUCL to
2409 ;; support printing of bfloats.
2411 (defun format-g (stream number colonp atp
2412 &optional w d e k overflowchar padchar marker
)
2415 (maxima::bfloat-format-g stream
(real-value number
) colonp atp
2418 (or padchar
#\space
)
2421 ;; FIXME: Do something better than this since this doesn't honor
2422 ;; any of the parameters.
2423 (princ number stream
))
2425 ;; We were given some other kind of object. Just use CL's normal
2426 ;; ~G printer to print it.
2428 (with-output-to-string (s)
2429 ;; Construct a suitable ~E format string from the given
2430 ;; parameters. First, handle w,d,e,k.
2431 (write-string "~V,V,V,V," s
)
2433 (format s
"'~C," overflowchar
)
2434 (write-string "," s
))
2436 (format s
"'~C," padchar
)
2437 (write-string "," s
))
2439 (format s
"'~C" marker
))
2444 (write-char #\G s
))))
2445 (format stream f w d e k number
)))))