Improve the translation of notequal
[maxima.git] / src / numeric.lisp
blobbabc46409f453c06560c6b0739abb24fb15c4961
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.
12 #+cmu
13 (eval-when (:compile-toplevel :load-toplevel :execute)
14 (setf lisp::*enable-package-locked-errors* nil))
16 (in-package #-gcl #:bigfloat #+gcl "BIGFLOAT")
18 (defun intofp (re)
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).
22 (cond ((floatp re)
23 (maxima::bcons (maxima::floattofp re)))
24 ((eql re 0)
25 (maxima::bcons '(0 0)))
26 ((integerp re)
27 (maxima::bcons (list (maxima::fpround re) (cl:+ maxima::*m maxima::fpprec))))
28 ((typep re 'ratio)
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))))
40 (defclass numeric ()
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
48 ;; why bother?
49 ((real :initform (intofp 0)
50 :initarg :real
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)
66 :initarg :real
67 :documentation "Real part of a complex bigfloat")
68 (imag :initform (intofp 0)
69 :initarg :imag
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
75 ;; fpprec.
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
81 ;; fpprec.
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
91 ;;;
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"
97 (cond (im
98 (make-instance 'complex-bigfloat
99 :real (intofp re)
100 :imag (intofp im)))
101 ((cl:realp re)
102 (make-instance 'bigfloat :real (intofp re)))
103 ((cl:complexp 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))
135 (if (typep z 'ratio)
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"
146 (real-value z))
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
152 (imag-value z))))
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))
170 (if (zerop x)
172 (cl:abs (nth-value 1 (cl:decode-float x)))))
174 (defmethod max-exponent ((x cl:rational))
175 (if (zerop x)
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))
195 (max-exponent a))))
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)))
206 `(let ((,result
207 (let ((,old-fpprec maxima::fpprec))
208 (unwind-protect
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
217 ;; precision.
218 `(,v (bigfloat:to (maxima::to ,v))))
219 varlist)
220 ,@body))
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)))))
226 ;;; REALP
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
230 ;; for gcl.
231 #-gcl
232 (defmethod realp ((x cl:real))
235 #+gcl
236 (progn
237 (defmethod realp ((x cl:rational))
239 (defmethod realp ((x cl:float))
244 (defmethod realp ((x bigfloat))
247 (defmethod realp ((x t))
248 nil)
250 ;;; COMPLEXP
251 (defmethod complexp ((x cl:complex))
254 (defmethod complexp ((x complex-bigfloat))
257 (defmethod complexp ((x t))
258 nil)
260 ;;; NUMBERP
261 (defmethod numberp ((x cl:number))
264 (defmethod numberp ((x bigfloat))
267 (defmethod numberp ((x complex-bigfloat))
270 (defmethod numberp ((x t))
271 nil)
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))
303 (defgeneric add1 (a)
304 (:documentation "Add 1"))
306 (defgeneric sub1 (a)
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
347 ;;; 1+ and 1-
349 (defmethod add1 ((a number))
350 (cl::1+ a))
352 (defmethod add1 ((a bigfloat))
353 (make-instance 'bigfloat
354 :real (maxima::bcons
355 (maxima::fpplus (cdr (real-value a))
356 (maxima::fpone)))))
358 (defmethod add1 ((a complex-bigfloat))
359 (make-instance 'complex-bigfloat
360 :real (maxima::bcons
361 (maxima::fpplus (cdr (real-value a))
362 (maxima::fpone)))
363 :imag (imag-value a)))
365 (defmethod sub1 ((a number))
366 (cl::1- a))
368 (defmethod sub1 ((a bigfloat))
369 (make-instance 'bigfloat
370 :real (maxima::bcons
371 (maxima::fpdifference (cdr (real-value a))
372 (maxima::fpone)))))
374 (defmethod sub1 ((a complex-bigfloat))
375 (make-instance 'complex-bigfloat
376 :real (maxima::bcons
377 (maxima::fpdifference (cdr (real-value a))
378 (maxima::fpone)))
379 :imag (imag-value a)))
381 (declaim (inline 1+ 1-))
383 (defun 1+ (x)
384 (add1 x))
386 (defun 1- (x)
387 (sub1 x))
389 ;; Add two numbers
390 (defmethod two-arg-+ ((a cl:number) (b cl:number))
391 (cl:+ a b))
393 (defmethod two-arg-+ ((a bigfloat) (b bigfloat))
394 (make-instance 'bigfloat
395 :real (maxima::bcons
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
401 :real (maxima::bcons
402 (maxima::fpplus (cdr (real-value a))
403 (cdr (real-value b))))
404 :imag (maxima::bcons
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
411 :real (maxima::bcons
412 (maxima::fpplus (cdr (real-value a))
413 (cdr (intofp b))))))
415 (defmethod two-arg-+ ((a bigfloat) (b cl:rational))
416 (make-instance 'bigfloat
417 :real (maxima::bcons
418 (maxima::fpplus (cdr (real-value a))
419 (cdr (intofp b))))))
421 (defmethod two-arg-+ ((a bigfloat) (b cl:complex))
422 (make-instance 'complex-bigfloat
423 :real (maxima::bcons
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))
429 (two-arg-+ b a))
431 (defmethod two-arg-+ ((a complex-bigfloat) (b bigfloat))
432 (make-instance 'complex-bigfloat
433 :real (maxima::bcons
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
440 :real (maxima::bcons
441 (maxima::fpplus (cdr (real-value a))
442 (cdr (intofp (cl:realpart b)))))
443 :imag (maxima::bcons
444 (maxima::fpplus (cdr (imag-value a))
445 (cdr (intofp (cl:imagpart b)))))))
447 (defmethod two-arg-+ ((a bigfloat) (b complex-bigfloat))
448 (two-arg-+ b a))
450 (defmethod two-arg-+ ((a number) (b complex-bigfloat))
451 (two-arg-+ b a))
453 (defun + (&rest args)
454 (if (null args)
456 (do ((args (cdr args) (cdr args))
457 (res (car args)
458 (two-arg-+ res (car args))))
459 ((null args) res))))
461 ;; Negate a number
462 (defmethod unary-minus ((a number))
463 (cl:- a))
465 (defmethod unary-minus ((a bigfloat))
466 (make-instance 'bigfloat
467 :real (maxima::bcons
468 (maxima::fpminus (cdr (real-value a))))))
470 (defmethod unary-minus ((a complex-bigfloat))
471 (make-instance 'complex-bigfloat
472 :real (maxima::bcons
473 (maxima::fpminus (cdr (real-value a))))
474 :imag (maxima::bcons
475 (maxima::fpminus (cdr (imag-value a))))))
477 ;;; Subtract two numbers
478 (defmethod two-arg-- ((a number) (b number))
479 (cl:- a b))
481 (defmethod two-arg-- ((a bigfloat) (b bigfloat))
482 (make-instance 'bigfloat
483 :real (maxima::bcons
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
489 :real (maxima::bcons
490 (maxima::fpdifference (cdr (real-value a))
491 (cdr (real-value b))))
492 :imag (maxima::bcons
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
499 :real (maxima::bcons
500 (maxima::fpdifference (cdr (real-value a))
501 (cdr (intofp b))))))
503 (defmethod two-arg-- ((a bigfloat) (b cl:rational))
504 (make-instance 'bigfloat
505 :real (maxima::bcons
506 (maxima::fpdifference (cdr (real-value a))
507 (cdr (intofp b))))))
509 (defmethod two-arg-- ((a bigfloat) (b cl:complex))
510 (make-instance 'complex-bigfloat
511 :real (maxima::bcons
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
518 :real (maxima::bcons
519 (maxima::fpdifference (cdr (intofp a))
520 (cdr (real-value b))))))
522 (defmethod two-arg-- ((a cl:rational) (b bigfloat))
523 (make-instance 'bigfloat
524 :real (maxima::bcons
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
533 :real (maxima::bcons
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))
539 (if (cl:complexp b)
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
545 :real (maxima::bcons
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))
551 (if (cl:complexp a)
552 (two-arg-- (bigfloat (cl:realpart a) (cl:imagpart a))
554 (two-arg-- (bigfloat a) b)))
556 (defun - (number &rest more-numbers)
557 (if more-numbers
558 (do ((nlist more-numbers (cdr nlist))
559 (result number))
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))
567 (cl:* a b))
569 (defmethod two-arg-* ((a bigfloat) (b bigfloat))
570 (make-instance 'bigfloat
571 :real (maxima::bcons
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
581 :real (maxima::bcons
582 (maxima::fpdifference (maxima::fptimes* a-re b-re)
583 (maxima::fptimes* a-im b-im)))
584 :imag (maxima::bcons
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
591 :real (maxima::bcons
592 (maxima::fptimes* (cdr (real-value a))
593 (cdr (intofp b))))))
595 (defmethod two-arg-* ((a bigfloat) (b cl:rational))
596 (make-instance 'bigfloat
597 :real (maxima::bcons
598 (maxima::fptimes* (cdr (real-value a))
599 (cdr (intofp b))))))
601 (defmethod two-arg-* ((a bigfloat) (b cl:complex))
602 (make-instance 'complex-bigfloat
603 :real (maxima::bcons
604 (maxima::fptimes* (cdr (real-value a))
605 (cdr (intofp (realpart b)))))
606 :imag (maxima::bcons
607 (maxima::fptimes* (cdr (real-value a))
608 (cdr (intofp (imagpart b)))))))
610 (defmethod two-arg-* ((a cl:number) (b bigfloat))
611 (two-arg-* b a))
613 (defmethod two-arg-* ((a complex-bigfloat) (b bigfloat))
614 (make-instance 'complex-bigfloat
615 :real (maxima::bcons
616 (maxima::fptimes* (cdr (real-value a))
617 (cdr (real-value b))))
618 :imag (maxima::bcons
619 (maxima::fptimes* (cdr (imag-value a))
620 (cdr (real-value b))))))
622 (defmethod two-arg-* ((a complex-bigfloat) (b number))
623 (if (cl:complexp b)
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))
628 (two-arg-* b a))
630 (defmethod two-arg-* ((a number) (b complex-bigfloat))
631 (two-arg-* b a))
633 (defun * (&rest args)
634 (if (null args)
636 (do ((args (cdr args) (cdr args))
637 (res (car args)
638 (two-arg-* res (car args))))
639 ((null args) res))))
641 ;;; Reciprocal of a number
642 (defmethod unary-divide ((a number))
643 (cl:/ a))
645 (defmethod unary-divide ((a bigfloat))
646 (make-instance 'bigfloat
647 :real (maxima::bcons
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))
661 :imag (maxima::bcons
662 (maxima::fpquotient (maxima::fpminus r)
663 dn))))
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))
668 :imag (maxima::bcons
669 (maxima::fpquotient (maxima::fpminus a-re)
670 dn)))))))
671 ;;; Divide two numbers
672 (defmethod two-arg-/ ((a number) (b number))
673 (cl:/ a b))
675 (defmethod two-arg-/ ((a bigfloat) (b bigfloat))
676 (make-instance 'bigfloat
677 :real (maxima::bcons
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
690 :real (maxima::bcons
691 (maxima::fpquotient
692 (maxima::fpplus a-re
693 (maxima::fptimes* a-im r))
694 dn))
695 :imag (maxima::bcons
696 (maxima::fpquotient
697 (maxima::fpdifference a-im
698 (maxima::fptimes* a-re r))
699 dn))))
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
703 :real (maxima::bcons
704 (maxima::fpquotient
705 (maxima::fpplus (maxima::fptimes* a-re r)
706 a-im)
707 dn))
708 :imag (maxima::bcons
709 (maxima::fpquotient (maxima::fpdifference
710 (maxima::fptimes* a-im r)
711 a-re)
712 dn)))))))
713 ;; Handle contagion for two-arg-/
714 (defmethod two-arg-/ ((a bigfloat) (b cl:float))
715 (make-instance 'bigfloat
716 :real (maxima::bcons
717 (maxima::fpquotient (cdr (real-value a))
718 (cdr (intofp b))))))
720 (defmethod two-arg-/ ((a bigfloat) (b cl:rational))
721 (make-instance 'bigfloat
722 :real (maxima::bcons
723 (maxima::fpquotient (cdr (real-value a))
724 (cdr (intofp b))))))
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
731 :real (maxima::bcons
732 (maxima::fpquotient (cdr (intofp a))
733 (cdr (real-value b))))))
735 (defmethod two-arg-/ ((a cl:rational) (b bigfloat))
736 (make-instance 'bigfloat
737 :real (maxima::bcons
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
747 :real (maxima::bcons
748 (maxima::fpquotient (cdr (real-value a))
749 (cdr (real-value b))))
750 :imag (maxima::bcons
751 (maxima::fpquotient (cdr (imag-value a))
752 (cdr (real-value b))))))
754 (defmethod two-arg-/ ((a complex-bigfloat) (b number))
755 (if (cl:complexp b)
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))
764 (if (cl:complexp a)
765 (two-arg-/ (bigfloat (cl:realpart a) (cl:imagpart a))
767 (two-arg-/ (bigfloat a) b)))
770 (defun / (number &rest more-numbers)
771 (if more-numbers
772 (do ((nlist more-numbers (cdr nlist))
773 (result number))
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)
780 (macrolet
781 ((frob (name)
782 (let ((cl-name (intern (symbol-name name) :cl)))
783 `(progn
784 (defmethod ,name ((x cl:float))
785 (,cl-name x))
786 (defmethod ,name ((x cl:rational))
787 (,cl-name x))))))
788 (frob plusp)
789 (frob minusp))
791 (defmethod zerop ((x number))
792 (cl:zerop x))
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)))))
811 ;;; Equality
812 (defmethod two-arg-= ((a number) (b number))
813 (cl:= a b))
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))
828 (two-arg-= b a))
830 (defmethod two-arg-= ((a complex-bigfloat) (b number))
831 (zerop (two-arg-- a b)))
833 (defmethod two-arg-= ((a number) (b complex-bigfloat))
834 (two-arg-= b a))
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)))
841 ((atom nlist) t)
842 (declare (list nlist))
843 (if (not (two-arg-= (car nlist) number))
844 (return nil))))
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)))
852 ((atom nlist) t)
853 (declare (list nlist))
854 (unless (do* ((nl nlist (cdr nl)))
855 ((atom nl) t)
856 (declare (list nl))
857 (if (two-arg-= head (car nl))
858 (return nil)))
859 (return nil))))
861 ;;; Comparison operations
862 (macrolet
863 ((frob (op)
864 (let ((method (intern (concatenate 'string
865 (string '#:two-arg-)
866 (symbol-name op))))
867 (cl-fun (find-symbol (symbol-name op) :cl)))
868 `(progn
869 (defmethod ,method ((a cl:float) (b cl:float))
870 (,cl-fun a b))
871 (defmethod ,method ((a cl:float) (b cl:rational))
872 (,cl-fun a b))
873 (defmethod ,method ((a cl:rational) (b cl:float))
874 (,cl-fun a b))
875 (defmethod ,method ((a cl:rational) (b cl:rational))
876 (,cl-fun a b))
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)))
883 ((atom nlist) t)
884 (declare (list nlist))
885 (if (not (,method n (car nlist))) (return nil))))))))
886 (frob <)
887 (frob >)
888 (frob <=)
889 (frob >=))
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)
967 (let ((d (gensym)))
968 `(let* (,@(mapcar #'list dummies vals)
969 (,d ,delta)
970 (,(car newval) (+ ,getter ,d)))
971 ,setter))))
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)
978 (let ((d (gensym)))
979 `(let* (,@(mapcar #'list dummies vals)
980 (,d ,delta)
981 (,(car newval) (- ,getter ,d)))
982 ,setter))))
986 ;;; Special functions for real-valued arguments
987 (macrolet
988 ((frob (name)
989 (let ((cl-name (intern (symbol-name name) :cl)))
990 `(progn
991 (defmethod ,name ((x number))
992 (,cl-name x))))))
993 (frob sqrt)
994 (frob abs)
995 (frob exp)
996 (frob sin)
997 (frob cos)
998 (frob tan)
999 (frob asin)
1000 (frob acos)
1001 (frob sinh)
1002 (frob cosh)
1003 (frob tanh)
1004 (frob asinh)
1005 (frob acosh)
1006 (frob atanh)
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))
1046 (if (minusp x)
1047 (make-instance 'complex-bigfloat
1048 :real (intofp 0)
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)
1058 (imag-value z))
1059 (make-instance 'complex-bigfloat
1060 :real (maxima::bcons rx)
1061 :imag (maxima::bcons ry))))
1063 (defmethod one-arg-log ((a number))
1064 (cl:log a))
1066 (defmethod one-arg-log ((a bigfloat))
1067 (if (minusp a)
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)
1077 (imag-value a))))
1078 (bigfloat res)))
1080 (defmethod two-arg-log ((a number) (b number))
1081 (cl:log a b))
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)
1093 (if b
1094 (two-arg-log a b)
1095 (one-arg-log a)))
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
1133 (macrolet
1134 ((frob (name &optional big-float-op-p)
1135 (if big-float-op-p
1136 (let ((big-op (intern (concatenate 'string
1137 (string '#:big-float-)
1138 (string name))
1139 '#:maxima)))
1140 `(defmethod ,name ((a complex-bigfloat))
1141 (let ((res (,big-op (real-value a)
1142 (imag-value a))))
1143 (to res))))
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))))
1150 (to result)))))))
1151 (frob exp)
1152 (frob sin)
1153 (frob cos)
1154 (frob tan)
1155 (frob asin t)
1156 (frob acos t)
1157 (frob sinh)
1158 (frob cosh)
1159 (frob tanh t)
1160 (frob asinh t)
1161 (frob acosh)
1162 (frob atanh t))
1164 (defmethod one-arg-atan ((a number))
1165 (cl:atan a))
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
1181 #-gcl
1182 (defmethod two-arg-atan ((a real) (b real))
1183 (cl:atan a b))
1185 #+gcl
1186 (progn
1187 (defmethod two-arg-atan ((a cl:float) (b cl:float))
1188 (cl:atan a b))
1189 (defmethod two-arg-atan ((a cl:rational) (b cl:rational))
1190 (cl:atan a b))
1191 (defmethod two-arg-atan ((a cl:float) (b cl:rational))
1192 (cl:atan a b))
1193 (defmethod two-arg-atan ((a cl:rational) (b cl:float))
1194 (cl:atan a b))
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)
1224 (if b
1225 (two-arg-atan a b)
1226 (one-arg-atan a)))
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)
1235 (real-value a)
1236 (declare (ignore marker))
1237 (make-instance 'bigfloat :real (maxima::bcons (list mantissa (+ exp n)))))))
1239 (macrolet
1240 ((frob (name)
1241 (let ((cl-name (intern (string name) '#:cl)))
1242 `(defmethod ,name ((a number))
1243 (,cl-name a)))))
1244 (frob realpart)
1245 (frob imagpart)
1246 (frob conjugate)
1247 (frob phase))
1249 (macrolet
1250 ((frob (name)
1251 (let ((cl-name (intern (string name) '#:cl)))
1252 `(defmethod ,name ((a number) &optional (divisor 1))
1253 (,cl-name a divisor)))))
1254 (frob floor)
1255 (frob ffloor)
1256 (frob ceiling)
1257 (frob fceiling)
1258 (frob truncate)
1259 (frob ftruncate)
1260 (frob round)
1261 (frob fround))
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))
1285 (cl:cis a))
1287 (defmethod cis ((a cl:rational))
1288 (cl:cis a))
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)))
1313 number)
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
1327 ;; instead.
1328 #-gcl
1329 (defmethod one-arg-complex ((a real))
1330 (cl:complex a))
1332 #+gcl
1333 (progn
1334 (defmethod one-arg-complex ((a cl:float))
1335 (cl:complex a))
1336 (defmethod one-arg-complex ((a cl:rational))
1337 (cl:complex a))
1340 (defmethod one-arg-complex ((a bigfloat))
1341 (make-instance 'complex-bigfloat
1342 :real (real-value a)
1343 :imag (intofp 0)))
1345 #-gcl
1346 (defmethod two-arg-complex ((a real) (b real))
1347 (cl:complex a b))
1349 #+gcl
1350 (progn
1351 (defmethod two-arg-complex ((a cl:float) (b cl:float))
1352 (cl:complex a b))
1353 (defmethod two-arg-complex ((a cl:rational) (b cl:rational))
1354 (cl:complex a b))
1355 (defmethod two-arg-complex ((a cl:float) (b cl:rational))
1356 (cl:complex a b))
1357 (defmethod two-arg-complex ((a cl:rational) (b cl:float))
1358 (cl:complex a b))
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
1368 :real (intofp a)
1369 :imag (real-value b)))
1371 (defmethod two-arg-complex ((a cl:rational) (b bigfloat))
1372 (make-instance 'complex-bigfloat
1373 :real (intofp a)
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)
1379 :imag (intofp b)))
1381 (defmethod two-arg-complex ((a bigfloat) (b cl:rational))
1382 (make-instance 'complex-bigfloat
1383 :real (real-value a)
1384 :imag (intofp b)))
1386 (defun complex (a &optional b)
1387 (if 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))))
1394 (cond ((minusp 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.
1398 (if (= trunc a)
1399 trunc
1400 (1- trunc)))
1402 trunc))))
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))
1410 (if (= 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))
1417 (if (= 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))
1432 (if (eql 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))
1439 (if (eql 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.
1447 (if (minusp a)
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))
1457 (if (eql 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))
1464 (if (eql 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)
1474 (if (zerop rem)
1475 (values tru rem)
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)))
1483 (or (< rem -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))
1497 (cl:expt a b))
1499 ;; This needs more work
1500 (defmethod expt ((a numeric) (b numeric))
1501 (if (zerop b)
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))
1506 (bigfloat 1))
1507 (cond ((and (zerop a) (plusp (realpart b)))
1508 (* a 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)
1515 (a b))
1516 (exp (* b (log a))))))))
1518 (defmethod expt ((a cl:number) (b numeric))
1519 (if (zerop b)
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))
1524 (bigfloat 1))
1525 (cond ((and (zerop a) (plusp (realpart b)))
1526 (* a b))
1527 ((and (realp b) (= b (truncate b)))
1528 (with-extra-precision ((expt-extra-bits a b)
1529 (a b))
1530 (intofp (expt a (truncate b)))))
1532 (with-extra-precision ((expt-extra-bits a b)
1533 (a b))
1534 (exp (* b (log (bigfloat a)))))))))
1536 (defmethod expt ((a numeric) (b cl:number))
1537 (if (zerop b)
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))
1542 (bigfloat 1))
1543 (if (and (zerop a) (plusp (realpart b)))
1544 (* a b)
1545 ;; Handle a few special cases using multiplication.
1546 (cond ((= b 1)
1548 ((= b -1)
1549 (/ a))
1550 ((= b 2)
1551 (* a a))
1552 ((= b -2)
1553 (/ (* a a)))
1554 ((= b 3) (* a a a))
1555 ((= b -3) (/ (* a a a)))
1556 ((= b 4)
1557 (let ((a2 (* a a)))
1558 (* a2 a2)))
1559 ((= b -4)
1560 (let ((a2 (* a a)))
1561 (/ (* a2 a2))))
1563 (with-extra-precision ((expt-extra-bits a b)
1564 (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))
1570 (cond ((zerop b)
1571 (bigfloat 1))
1572 ((and (zerop a) (plusp b))
1573 ;; 0^b, for positive b
1574 (* a b))
1575 ;; Handle a few special cases using multiplication.
1576 ((eql b 1) a)
1577 ((eql b -1) (/ a))
1578 ((eql b 2) (* a a))
1579 ((eql b -2) (/ (* a a)))
1580 ((eql b 3) (* a a a))
1581 ((eql b -3) (/ (* a a a)))
1582 ((eql b 4)
1583 (let ((a2 (* a a)))
1584 (* a2 a2)))
1585 ((eql b -4)
1586 (let ((a2 (* a a)))
1587 (/ (* a2 a2))))
1588 ((minusp 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)
1593 (a b))
1594 (* (exp (* b (log (abs a))))
1595 (if (oddp b) -1 1))))
1597 (with-extra-precision ((expt-extra-bits a b)
1598 (a b))
1599 (exp (* b (log a)))))))
1601 ;;; TO - External
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))))
1609 (or result
1610 (maxima::merror (intl:gettext "BIGFLOAT: unable to convert ~M to a CL or BIGFLOAT number.")
1611 (if imag
1612 (maxima::add maxima-num (maxima::mul imag 'maxima::$%i))
1613 maxima-num)))))
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))))
1621 (or result
1622 (if imag
1623 (maxima::add maxima-num imag)
1624 maxima-num))))
1626 (defun %to (maxima-num &optional imag)
1627 (cond (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.
1633 #-clisp
1634 (complex (to maxima-num) (to imag))
1635 #+clisp
1636 (let ((re (to maxima-num))
1637 (im (to imag)))
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))))
1642 (complex re im)))
1644 (cond ((cl:numberp maxima-num)
1645 maxima-num)
1646 ((eq maxima-num 'maxima::$%i)
1647 ;; Convert %i to an exact complex cl:rational.
1648 #c(0 1))
1649 ((consp maxima-num)
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)
1657 (or (cl:realp x)
1658 (maxima::$bfloatp x)
1659 (and (consp 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
1663 ;; cl:rational.
1664 (let ((re (maxima::$realpart maxima-num))
1665 (im (maxima::$imagpart maxima-num)))
1666 (to re im)))))
1667 ((or (typep maxima-num 'bigfloat)
1668 (typep maxima-num 'complex-bigfloat))
1669 maxima-num)
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))
1677 (etypecase x
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
1698 ;; for -, *, and /.
1699 (define-compiler-macro + (&whole form &rest args)
1700 (declare (ignore form))
1701 (if (null args)
1703 (do ((args (cdr args) (cdr args))
1704 (res (car 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))
1710 (if more-numbers
1711 (do ((nlist more-numbers (cdr nlist))
1712 (result number))
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))
1720 (if (null args)
1722 (do ((args (cdr args) (cdr args))
1723 (res (car args)
1724 `(two-arg-* ,res ,(car args))))
1725 ((null args) res))))
1727 (define-compiler-macro / (number &rest more-numbers)
1728 (if more-numbers
1729 (do ((nlist more-numbers (cdr nlist))
1730 (result number))
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)
1740 form
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.
1745 (macrolet
1746 ((frob (op)
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))
1753 (res nil))
1754 ((atom nlist)
1755 `(and ,@(nreverse res)))
1756 (push `(,',method ,n ,(car nlist)) res))))))
1757 (frob <)
1758 (frob >)
1759 (frob <=)
1760 (frob >=))
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)))
1778 (third r)
1779 (bigfloat (signum (second r))))))
1781 ;; GCL doesn't have a REAL class!
1782 #+gcl
1783 (progn
1784 (defmethod float ((x cl:float) (y cl:float))
1785 (cl:float x y))
1787 (defmethod float ((x cl:rational) (y cl:float))
1788 (cl:float x y))
1790 (defmethod float ((x cl:float) (y bigfloat))
1791 (bigfloat x))
1793 (defmethod float ((x cl:rational) (y bigfloat))
1794 (bigfloat x))
1797 #-gcl
1798 (progn
1799 (defmethod float ((x real) (y cl:float))
1800 (cl:float x y))
1802 (defmethod float ((x real) (y bigfloat))
1803 (bigfloat x))
1806 ;; Like Maxima's fp2flo, but for single-float numbers.
1807 (defun fp2single (l)
1808 (let ((precision (caddar l))
1809 (mantissa (cadr l))
1810 (exponent (caddr l))
1811 (fpprec (float-digits 1f0))
1812 (maxima::*m 0))
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)
1817 (expt 2f0 fpprec)))
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
1844 ;; correct range.
1845 (if (plusp x)
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))
1851 (cl:signum x))
1853 (defmethod signum ((x bigfloat))
1854 (cond ((minusp x)
1855 (bigfloat -1))
1856 ((plusp x)
1857 (bigfloat 1))
1859 x)))
1861 (defmethod signum ((x complex-bigfloat))
1862 (/ x (abs x)))
1864 (defmethod float-sign ((x cl:float))
1865 (cl:float-sign x))
1867 (defmethod float-sign ((x bigfloat))
1868 (if (minusp x)
1869 (bigfloat -1)
1870 (bigfloat 1)))
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)))
1880 (third (first r))))
1882 #-gcl
1883 (defmethod rational ((x real))
1884 (cl:rational x))
1886 #+gcl
1887 (progn
1888 (defmethod rational ((x cl:float))
1889 (cl:rational x))
1890 (defmethod rational ((x cl:rational))
1891 (cl:rational x))
1894 (defmethod rational ((x bigfloat))
1895 (destructuring-bind ((marker simp prec) mantissa exp)
1896 (real-value x)
1897 (declare (ignore marker simp))
1898 (* mantissa (expt 2 (- exp prec)))))
1900 #-gcl
1901 (defmethod rationalize ((x real))
1902 (cl:rationalize x))
1904 #+gcl
1905 (progn
1906 (defmethod rationalize ((x cl:float))
1907 (cl:rationalize x))
1908 (defmethod rationalize ((x cl:rational))
1909 (cl:rationalize x))
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))).
1928 ;;; If x > 0.0:
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
1940 ;;; interval (a,b).
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)
1945 ;;; if c < b
1946 ;;; then return c ; because a <= c < b, c integer
1947 ;;; else
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.
1965 ;;; Loop
1966 ;;; c := (ceiling a)
1967 ;;; if c >= b
1968 ;;; then k := c-1, partial_quotient(k), (a,b) := (1/(b-k),1/(a-k)),
1969 ;;; goto Loop
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))
1981 (if (minusp sign)
1982 (- (ash frac expo))
1983 (ash frac expo)))
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
1987 ;; a gcd.
1988 (let ((a (/ (- (* 2 frac) 1) (ash 1 (- 1 expo))))
1989 (b (/ (+ (* 2 frac) 1) (ash 1 (- 1 expo))))
1990 (p0 0)
1991 (q0 1)
1992 (p1 1)
1993 (q1 0))
1994 (do ((c (ceiling a) (ceiling a)))
1995 ((< c b)
1996 (let ((top (+ (* c p1) p0))
1997 (bot (+ (* c q1) q0)))
1998 (/ (if (minusp sign)
1999 (- top)
2000 top)
2001 bot)))
2002 (let* ((k (- c 1))
2003 (p2 (+ (* k p1) p0))
2004 (q2 (+ (* k q1) q0)))
2005 (psetf a (/ (- b k))
2006 b (/ (- a k)))
2007 (setf p0 p1
2008 q0 q1
2009 p1 p2
2010 q1 q2))))))))
2012 (defun coerce (obj type)
2013 (flet ((coerce-error ()
2014 (error "Cannot coerce ~A to type ~S" obj type)))
2015 (cond ((typep obj type)
2016 obj)
2017 ((subtypep type 'bigfloat)
2018 ;; (coerce foo 'bigfloat). Foo has to be a real
2019 (cond ((typep obj 'real)
2020 (bigfloat obj))
2022 (coerce-error))))
2023 ((subtypep type 'complex-bigfloat)
2024 ;; (coerce foo 'complex-bigfloat). Foo has to be a real or complex
2025 (cond ((typep obj 'real)
2026 (bigfloat obj 0))
2027 ((typep obj 'cl:complex)
2028 (bigfloat obj))
2029 ((typep obj 'bigfloat)
2030 (bigfloat obj 0))
2032 (coerce-error))))
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)))
2054 (coerce-error))))
2055 ((typep obj 'complex-bigfloat)
2056 ;; (coerce complex-bigfloat foo)
2057 (cond ((subtypep type 'complex-bigfloat)
2058 obj)
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)))
2069 (coerce-error))))
2071 (cl:coerce obj type)))))
2073 ;;; %PI - External
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))
2081 (cl:float cl:pi x))
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))))
2092 ;;; %e - External
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*
2124 10000
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:
2135 ;;; a1 a2 a3
2136 ;;; b0 + ---- ---- ----
2137 ;;; b1 + b2 + b3 +
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.
2147 (if (zerop v)
2148 (progn
2149 (incf tiny-value-count)
2150 (etypecase v
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))))))
2159 v)))
2160 (let* ((f (value-or-tiny (funcall bf 0)))
2161 (c f)
2162 (d 0)
2163 (eps (epsilon f)))
2164 (loop
2165 for j from 1 upto *max-cf-iterations*
2166 for an = (funcall af j)
2167 for bn = (funcall bf j)
2168 do (progn
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)))
2178 (setf d (/ 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)))))
2185 finally
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)))
2204 (do* ((k 1 (+ 1 k))
2205 (sum 1 (+ sum term))
2206 (term (* x (funcall f 1))
2207 (* term x (funcall f k))))
2208 ((< (abs term) (* eps (abs sum)))
2209 sum)
2210 #+nil
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
2219 &optional w d e k
2220 overflowchar padchar exponentchar)
2221 (typecase number
2222 (bigfloat
2223 (maxima::bfloat-format-e stream (real-value number) colonp atp
2224 w d e (or k 1)
2225 overflowchar
2226 (or padchar #\space)
2227 (or exponentchar #\b)))
2228 (complex-bigfloat
2229 ;; FIXME: Do something better than this since this doesn't honor
2230 ;; any of the parameters.
2231 (princ number stream))
2232 (otherwise
2233 ;; We were given some other kind of object. Just use CL's normal
2234 ;; ~E printer to print it.
2235 (let ((f
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)
2240 (if overflowchar
2241 (format s "'~C," overflowchar)
2242 (write-string "," s))
2243 (if padchar
2244 (format s "'~C," padchar)
2245 (write-string "," s))
2246 (when exponentchar
2247 (format s "'~C" exponentchar))
2248 (when colonp
2249 (write-char #\: s))
2250 (when atp
2251 (write-char #\@ s))
2252 (write-char #\E s))))
2253 (format stream f w d e k number)))))
2256 (defmacro assert-equal (expected form)
2257 (let ((result (gensym))
2258 (e (gensym)))
2259 `(let ((,e ,expected)
2260 (,result ,form))
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
2305 "~9,4,,-7E"
2306 (bigfloat:bigfloat pi)))
2307 (assert-equal ".000003d+6" (format nil
2308 "~9,4,,-5E"
2309 (bigfloat:bigfloat pi)))
2310 (assert-equal "3141600.d-6" (format nil
2311 "~5,4,,7E"
2312 (bigfloat:bigfloat pi)))
2313 (assert-equal " 314.16d-2" (format nil
2314 "~11,4,,3E"
2315 (bigfloat:bigfloat pi)))
2316 (assert-equal " 31416.d-4" (format nil
2317 "~11,4,,5E"
2318 (bigfloat:bigfloat pi)))
2319 (assert-equal " 0.3142d+1" (format nil
2320 "~11,4,,0E"
2321 (bigfloat:bigfloat pi)))
2322 (assert-equal ".03142d+2" (format nil
2323 "~9,,,-1E"
2324 (bigfloat:bigfloat pi)))
2325 (assert-equal "0.003141592653589793d+3" (format nil
2326 "~,,,-2E"
2327 (bigfloat:bigfloat pi)))
2328 (assert-equal "31.41592653589793d-1" (format nil
2329 "~,,,2E"
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)))
2347 ;; Works
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)
2374 (typecase number
2375 (bigfloat
2376 (maxima::bfloat-format-f stream (real-value number) colonp atp
2377 w d (or k 0)
2378 overflowchar
2379 (or padchar #\space)))
2380 (complex-bigfloat
2381 ;; FIXME: Do something better than this since this doesn't honor
2382 ;; any of the parameters.
2383 (princ number stream))
2384 (otherwise
2385 ;; We were given some other kind of object. Just use CL's normal
2386 ;; ~F printer to print it.
2387 (let ((f
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)
2392 (if overflowchar
2393 (format s "'~C," overflowchar)
2394 (write-string "," s))
2395 (if (char= padchar #\space)
2396 (write-string "," s)
2397 (format s "'~C," padchar))
2398 (when colonp
2399 (write-char #\: s))
2400 (when atp
2401 (write-char #\@ s))
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)
2412 (typecase number
2413 (bigfloat
2414 (maxima::bfloat-format-g stream (real-value number) colonp atp
2415 w d e (or k 1)
2416 overflowchar
2417 (or padchar #\space)
2418 (or marker #\b)))
2419 (complex-bigfloat
2420 ;; FIXME: Do something better than this since this doesn't honor
2421 ;; any of the parameters.
2422 (princ number stream))
2423 (otherwise
2424 ;; We were given some other kind of object. Just use CL's normal
2425 ;; ~G printer to print it.
2426 (let ((f
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)
2431 (if overflowchar
2432 (format s "'~C," overflowchar)
2433 (write-string "," s))
2434 (if padchar
2435 (format s "'~C," padchar)
2436 (write-string "," s))
2437 (when marker
2438 (format s "'~C" marker))
2439 (when colonp
2440 (write-char #\: s))
2441 (when atp
2442 (write-char #\@ s))
2443 (write-char #\G s))))
2444 (format stream f w d e k number)))))