1 ;;;; portable implementations or stubs for nonportable floating point
2 ;;;; things, useful for building Python as a cross-compiler when
3 ;;;; running under an ordinary ANSI Common Lisp implementation
5 ;;;; This software is part of the SBCL system. See the README file for
8 ;;;; This software is derived from the CMU CL system, which was
9 ;;;; written at Carnegie Mellon University and released into the
10 ;;;; public domain. The software is in the public domain and is
11 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
12 ;;;; files for more information.
14 (in-package "SB-IMPL")
16 (defun float-sign-bit (float)
17 (declare (type float float
))
18 (logand (ash (flonum-bits float
)
19 (- (1- (etypecase float
23 (defun float-sign-bit-set-p (float)
24 (declare (type float float
))
25 (= (float-sign-bit float
) 1))
26 (declaim (inline flonum-minus-zero-p
))
27 (defun flonum-minus-zero-p (flonum)
28 (or (eq flonum -
0.0f0
) (eq flonum -
0.0d0
)))
30 (defun pick-result-format (&rest args
)
31 (flet ((target-num-fmt (num)
32 (cond ((rationalp num
) 'rational
)
33 ((floatp num
) (type-of num
))
34 (t (error "What? ~S" num
)))))
35 (let* ((result-fmt 'rational
)
37 (dolist (arg args result-fmt
)
38 (let* ((arg-fmt (target-num-fmt arg
))
39 ;; This is inadequate for complex numbers,
40 ;; but we don't need them.
43 '(rational short-float single-float double-float long-float
))))
44 (when (cl:> arg-contagion result-contagion
)
45 (setq result-fmt arg-fmt result-contagion arg-contagion
)))))))
47 (defun pick-float-result-format (&rest args
)
48 (let ((format (apply #'pick-result-format args
)))
49 (if (eq format
'rational
)
53 (defun rationalize (x)
56 (let ((rational (rational x
)))
57 (if (integerp rational
)
59 (error "Won't do (RATIONALIZE ~S) due to possible precision loss" x
)))))
61 (defun xfloat-coerce (object type
)
62 (declare (number object
))
63 (when (member type
'(integer rational real
))
64 ;; This branch won't accept (coerce x 'real) if X is one of our
65 ;; target-floats. We don't need that apparently.
66 (assert (if (eq type
'integer
) (integerp object
) (rationalp object
)))
67 (return-from xfloat-coerce object
))
68 (unless (member type
'(float short-float single-float double-float long-float
))
69 (error "Can't COERCE ~S ~S" object type
))
70 (when (and (floatp object
)
71 (or (eq type
'float
) (eq (type-of object
) type
)))
72 (return-from xfloat-coerce object
))
73 (with-memoized-math-op (coerce (list object type
))
74 (cond ((not (realp object
))
75 (error "Can't COERCE ~S ~S" object type
))
76 ((and (flonum-minus-zero-p object
)
77 (member type
'(double-float single-float
)))
78 (ecase type
(single-float -
0.0f0
) (double-float -
0.0d0
)))
80 (float-infinity-p object
))
83 (if (float-sign-bit-set-p object
)
84 single-float-negative-infinity
85 single-float-positive-infinity
))
87 (if (float-sign-bit-set-p object
)
88 double-float-negative-infinity
89 double-float-positive-infinity
))))
91 (let ((actual-type (if (member type
'(double-float long-float
))
94 (source-value (rational object
)))
95 (flonum-from-rational source-value actual-type
))))))
98 (if (float-sign-bit-set-p x
)
102 ;;; Signum should return -0 of the correct type for -0 input.
103 ;;; We don't need it currently.
104 (defun xfloat-signum (x)
109 (macrolet ((define (name float-fun
)
110 (declare (ignore name
))
111 `(defun ,float-fun
(number divisor
)
112 (declare (ignore number divisor
))
113 (error "Unimplemented"))))
114 (define mod xfloat-mod
)
115 (define rem xfloat-rem
))
117 (macrolet ((define (name float-fun
)
118 (let ((clname (intern (string name
) "CL")))
119 `(defun ,float-fun
(number divisor
)
120 (let ((type (pick-float-result-format number divisor
)))
121 (with-memoized-math-op (,name
(list number divisor
))
122 (if (flonum-minus-zero-p number
)
124 (coerce (if (< divisor
0) 0 -
0.0) type
))
125 (multiple-value-bind (q r
)
126 (,clname
(rational number
) (rational divisor
))
127 (values q
(flonum-from-rational r type
))))))))))
128 (define floor xfloat-floor
)
129 (define ceiling xfloat-ceiling
)
130 (define truncate xfloat-truncate
)
131 (define round xfloat-round
))
134 ;; return 1 or -1 if the sign bit of THING (as if converted to
135 ;; FLONUM) is unset or set respectively.
138 (rational (signum thing
))
139 (float (if (float-sign-bit-set-p thing
) -
1 1))))
141 (macrolet ((define (name clname
)
142 `(defun ,name
(number &optional
(divisor 1 divisorp
))
143 (with-memoized-math-op (,name
(if divisorp
(list number divisor
) number
))
144 (multiple-value-bind (q r
)
145 (,clname
(rational number
) (rational divisor
))
146 (let* ((type (pick-float-result-format number divisor
))
147 (format (pick-result-format number divisor
))
148 (remainder (if (eql format
'rational
)
150 (flonum-from-rational r format
))))
152 (values (coerce (if (cl:= (sgn number
) (sgn divisor
)) 0 -
0.0)
155 (values (flonum-from-rational q type
) remainder
))))))))
156 (define fceiling cl
:ceiling
)
157 (define ffloor cl
:floor
)
158 (define fround cl
:round
)
159 (define ftruncate cl
:truncate
))
161 (defun xfloat-expt (base power
)
162 (if (not (integerp power
))
163 (error "Unimplemented: EXPT with non-integer power")
164 (with-memoized-math-op (expt (list base power
))
166 (coerce 1 (type-of base
))
167 (flonum-from-rational
168 (cl:expt
(rational base
) power
)
169 (pick-result-format base power
))))))
171 ;;; Four possible return values. NIL if the numbers (rationals or
172 ;;; flonums) are incomparable (either is a NaN). Otherwise: -1, 0, 1
173 ;;; if A is less than, equal to or greater than B.
174 (defun numeric-compare (a b
)
176 ((or (and (floatp a
) (float-nan-p a
))
177 (and (floatp b
) (float-nan-p b
)))
179 ((and (and (floatp a
) (float-infinity-p a
))
180 (and (floatp b
) (float-infinity-p b
)))
181 (let ((sa (float-sign-bit a
))
182 (sb (float-sign-bit b
)))
185 ;; sign bit is 1 if flonum is negative
186 (if (cl:< sa sb
) 1 -
1))))
187 ((and (floatp a
) (float-infinity-p a
))
188 (if (cl:= (float-sign-bit a
) 1) -
1 1))
189 ((and (floatp b
) (float-infinity-p b
))
190 (if (cl:= (float-sign-bit b
) 1) 1 -
1))
192 (t (let ((ra (rational a
))
196 (if (cl:< ra rb
) -
1 1))))))
198 (defmacro define-flonum-comparator
(name form
)
199 (let ((clname (intern (string name
) "CL")))
200 `(defun ,name
(&rest args
)
201 (if (every #'rationalp args
)
202 (apply #',clname args
)
203 (with-memoized-math-op (,clname args
)
204 (loop for
(a b
) on args
206 always
(let ((c (numeric-compare a b
)))
209 (define-flonum-comparator sb-xc
:< (eql c -
1))
210 (define-flonum-comparator sb-xc
:<= (or (eql c -
1) (eql c
0)))
211 (define-flonum-comparator sb-xc
:= (eql c
0))
212 (define-flonum-comparator sb-xc
:>= (or (eql c
0) (eql c
1)))
213 (define-flonum-comparator sb-xc
:> (eql c
1))
215 ;;; what should (/= NaN NaN) return? I'm not convinced that we have a
216 ;;; consistent story. On the other hand it looks like we never call
217 ;;; /= in cross-compilation, let alone /= on NaNs.
218 (defun sb-xc:/= (&rest args
)
219 (if (every #'rationalp args
)
221 (with-memoized-math-op (/= args
)
222 (loop for
(a . rest
) on args
223 always
(loop for b in rest
224 for c
= (numeric-compare a b
)
225 always
(cl:/= c
0))))))
227 (defmacro define-flonum-extremizer
(name comparator
)
228 (let ((clname (intern (string name
) "CL")))
229 `(defun ,name
(arg &rest rest
&aux
(args (cons arg rest
)))
230 (if (every #'rationalp args
)
231 (apply #',clname args
)
232 (with-memoized-math-op (,clname args
)
235 (when (,comparator a ret
)
238 (define-flonum-extremizer sb-xc
:max sb-xc
:>)
239 (define-flonum-extremizer sb-xc
:min sb-xc
:<)
241 (defun wrap-two-arg-fun (fun value
)
242 (lambda (&optional
(x nil xp
) y
)
243 (if xp
(funcall fun x y
) value
)))
245 (defun sb-xc:+ (&rest args
)
246 (flet ((two-arg-+ (x y
)
247 (let ((format (pick-result-format x y
)))
249 ((eql format
'rational
) (cl:+ x y
))
250 ((and (flonum-minus-zero-p x
)
251 (flonum-minus-zero-p y
))
252 (coerce -
0.0 format
))
253 (t (flonum-from-rational (cl:+ (rational x
) (rational y
)) format
))))))
254 (if (every #'rationalp args
)
256 (with-memoized-math-op (+ args
)
257 (reduce (wrap-two-arg-fun #'two-arg-
+ 0) args
)))))
259 (defun sb-xc:-
(arg &rest rest
&aux
(args (cons arg rest
)))
260 (flet ((one-arg-- (x)
263 (single-float (make-single-float (logxor (ash -
1 31) (single-float-bits x
))))
264 (double-float (%make-double-float
(logxor (ash -
1 63) (double-float-bits x
))))))
266 (let ((format (pick-result-format x y
)))
268 ((eql format
'rational
) (cl:- x y
))
269 ((and (flonum-minus-zero-p x
)
270 (and (zerop y
) (not (flonum-minus-zero-p y
))))
271 (coerce -
0.0 format
))
272 (t (flonum-from-rational (cl:-
(rational x
) (rational y
)) format
))))))
273 (if (every #'rationalp args
)
275 (with-memoized-math-op (- args
)
278 (reduce #'two-arg-- args
))))))
280 (defun sb-xc:* (&rest args
)
281 (flet ((two-arg-* (x y
)
282 (let ((format (pick-result-format x y
)))
284 ((eql format
'rational
) (cl:* x y
))
285 ((or (and (floatp x
) (float-infinity-p x
))
286 (and (floatp y
) (float-infinity-p y
)))
287 (when (or (zerop x
) (zerop y
))
288 (error "Can't multiply infinity with 0."))
289 (coerce (if (cl:= (sgn x
) (sgn y
))
290 single-float-positive-infinity
291 single-float-negative-infinity
)
293 ((or (flonum-minus-zero-p x
)
294 (flonum-minus-zero-p y
))
295 (coerce (if (cl:= (sgn x
) (sgn y
)) 0 -
0.0) format
))
296 (t (flonum-from-rational (cl:* (rational x
) (rational y
)) format
))))))
297 (if (every #'rationalp args
)
299 (with-memoized-math-op (* args
)
300 (reduce (wrap-two-arg-fun #'two-arg-
* 1) args
)))))
302 (defun sb-xc:/ (arg &rest rest
&aux
(args (cons arg rest
)))
303 (flet ((one-arg-/ (x)
305 ((rationalp x
) (cl:/ x
))
307 (float-sign x single-float-positive-infinity
))
308 (t (flonum-from-rational (cl:/ (rational x
)) (type-of x
)))))
310 (let ((format (pick-result-format x y
)))
312 ((eql format
'rational
) (cl:/ x y
))
313 ((and (zerop x
) (zerop y
))
314 (error "can't represent NaN for (/ 0 0)"))
316 (error "can't represent Inf for (/ x 0)"))
318 (coerce (if (cl:= (sgn x
) (sgn y
)) 0 -
0.0) format
))
319 (t (flonum-from-rational (cl:/ (rational x
) (rational y
)) format
))))))
320 (if (every #'rationalp args
)
322 (with-memoized-math-op (/ args
)
325 (reduce #'two-arg-
/ args
))))))
327 (defun %sqrt
(rational)
328 (flet ((%%sqrt
(rational initial
)
329 (let ((current initial
))
330 ;; why 7? our initial "guess" has at least ~1 bit of
331 ;; precision (for e.g. RATIONAL = 2), and each iteration
332 ;; gives 2n+1 bits, so 7 gives ~127 bits, which should be
333 ;; enough for everybody.
334 (dotimes (i 7 current
)
335 (setf current
(cl:/ (cl:+ current
(cl:/ rational current
)) 2))))))
336 (%%sqrt rational
(cl:/ (isqrt (numerator rational
)) (isqrt (denominator rational
))))))
338 (defun sb-xc:sqrt
(arg)
339 (let ((format (if (rationalp arg
) 'single-float
(type-of arg
))))
340 (with-memoized-math-op (sqrt arg
)
341 (flonum-from-rational (%sqrt
(rational arg
)) format
))))
343 ;;; There seems to be no portable way to mask float traps, so right
344 ;;; now we ignore them and hardcode special cases.
345 (defmacro sb-vm
::with-float-traps-masked
(traps &body body
)
346 (declare (ignore traps
))
348 (format *error-output
*
349 "~&(can't portably mask float traps, proceeding anyway)~%")
352 (defun realpart (x) (if (realp x
) x
(complexnum-real x
)))
354 (cond ((rationalp x
) 0)
355 ((single-float-p x
) 0f0
)
356 ((double-float-p x
) 0d0
)
357 (t (complexnum-imag x
))))
359 (defun sb-vm::sign-extend
(x size
)
360 (if (logbitp (1- size
) x
) (cl:dpb x
(cl:byte size
0) -
1) x
))
362 ;;; PI is needed in order to build the cross-compiler mainly so that vm-fndb
363 ;;; can define bounds on irrational functions.
364 (defconstant pi
3.14159265358979323846264338327950288419716939937511L0)
366 (macrolet ((def (name lambda-list
)
367 `(defun ,(intern (string name
) "SB-XC") ,lambda-list
368 (declare (ignorable ,@lambda-list
))
369 (error "Unimplemented."))))
376 (def conjugate
(number))
385 (defun atan (number1 &optional
(number2 nil number2p
))
387 (with-memoized-math-op (atan (list number1 number2
))
388 (error "Unimplemented."))
389 (with-memoized-math-op (atan number1
)
390 (if (eql number1
1.4916681462400417d-154
)
392 (error "Unimplemented.")))))
395 (with-memoized-math-op (cosh number
)
399 (t (error "Unimplemented.")))))
401 (defun natural-log (number)
402 (declare (rational number
))
404 (declare (rational y
))
405 (assert (<= 1/2 y
1))
406 ;; Use the Taylor series expansion for log((1-y)/(1+y)),
407 ;; which gives around 4*m bits of precision for m terms
408 ;; when 1/2 <= y <= 1.
409 (let* ((x (/ (- y
1) (+ y
1)))
414 ;; 40 * 4 = 160 bits of precision.
415 ((>= k
40) (* 2 sum
))
416 (incf sum
(/ x^k k
))))))
417 ;; Write NUMBER as 2^k * a, so that 1/2 < a <= 1. Then log(NUMBER)
418 ;; is log(a) - k * log(1/2).
419 (let* ((k (1+ (- (integer-length (numerator number
))
420 (integer-length (denominator number
)))))
421 (a (/ number
(expt 2 k
))))
422 (- (%log a
) (* k
(%log
1/2))))))
424 (defun log (number &optional
(base nil base-p
))
425 (validate-args number base
)
427 (error 'division-by-zero
:operation
'log
:operands
`(,number
,@(when base-p base
))))
428 (with-memoized-math-op (log (if base-p
(list number base
) number
))
429 (let ((format (pick-float-result-format number
(if base-p base
0))))
431 (coerce single-float-negative-infinity format
)
432 (flonum-from-rational (/ (natural-log (rational number
))
434 (natural-log (rational base
))
438 ;;; Canonicalize and write out the memoization table.
439 (defun dump-math-memoization-table (table stream
)
440 (format stream
";;; This file is machine-generated. DO NOT EDIT~2%")
441 (format stream
"~%(~%")
442 (labels ((spelling-of (expr)
443 ;; MUST not write package prefixes !
444 ;; e.g. avoid writing a line like (COERCE (-33619991 SB-XC:DOUBLE-FLOAT) ...)
446 (write-to-string expr
:pretty nil
:escape t
)
447 (let ((hex (write-to-string expr
:pretty nil
:base
16 :radix t
:escape nil
))
448 (dec (write-to-string expr
:pretty nil
:base
10 :escape nil
)))
449 (if (<= (length hex
) (length dec
))
452 ;; Record each <fun,args> combination to STREAM
453 ;; Though all symbols we print, such as SINGLE-FLOAT, are accessible
454 ;; in any of the SB- packages, ABCL would buggily output package prefixes
455 ;; if ~S is used here.
456 (let ((*print-pretty
* nil
))
457 (maphash (lambda (key result
)
458 (destructuring-bind (fun . args
) key
459 (format stream
"(~A ~A~{ ~A~})~%"
461 ;; Why do ABS and RATIONAL write the unary arg as an atom
462 ;; but SQRT writes it as a singleton list?
464 (mapcar #'spelling-of args
)
466 ;; Can't use ENSURE-LIST. We need NIL -> (NIL)
471 (format stream
")~%"))
473 (defun show-interned-numbers (stream)
474 (flet ((to-native (x)
475 (declare (ignorable x
))
482 (host-sb-kernel:make-single-float
(flonum-bits r
)))
484 (host-sb-kernel:make-double-float
485 (double-float-high-bits r
)
486 (double-float-low-bits r
)))))))
488 (cl:complex
(realize (complexnum-real x
))
489 (realize (complexnum-imag x
)))
492 (format stream
"~2&; Interned flonums:~%")
493 (dolist (table (list *interned-single-floats
*
494 *interned-double-floats
*
495 *interned-complex-numbers
*))
496 (maphash (lambda (k v
)
497 (let ((actual (to-native v
)))
498 (format stream
"; ~S -> ~S~@[ = ~D~]~%" k v actual
)
500 (when (member actual values
)
501 ;; Duplicates means that the host's EQL
502 ;; would not answer correctly for certain inputs.
503 (error "Duplicate float in interned flonum table"))
504 (push actual values
))))
507 ;;; Perform some simple checks
508 (assert (not (eq -
0.0f0 -
0.0d0
)))
509 (assert (not (eq single-float-negative-infinity
0f0
)))
510 (dolist (format '(single-float double-float
))
511 (assert (zerop (coerce 0 format
)))
512 (assert (zerop (coerce -
0.0 format
)))
513 (assert (float-infinity-p (coerce single-float-positive-infinity format
)))
514 (assert (float-infinity-or-nan-p (coerce single-float-positive-infinity format
)))
515 (assert (not (float-nan-p (coerce single-float-positive-infinity format
))))
516 (assert (float-infinity-p (coerce single-float-negative-infinity format
)))
517 (assert (float-infinity-or-nan-p (coerce single-float-negative-infinity format
)))
518 (assert (not (float-nan-p (coerce single-float-negative-infinity format
))))
519 (assert (eq (coerce -
0.0 format
) (coerce -
0.0 format
)))
520 (assert (eq (coerce single-float-positive-infinity format
)
521 (coerce single-float-positive-infinity format
)))
522 (assert (eq (coerce single-float-negative-infinity format
)
523 (coerce single-float-negative-infinity format
)))
524 (assert (eq (sb-xc:+ (coerce -
0.0 format
) (coerce 0 format
)) (coerce 0 format
)))
525 (assert (eq (sb-xc:+ (coerce 0 format
) (coerce -
0.0 format
)) (coerce 0 format
)))
526 (assert (eq (sb-xc:+ (coerce -
0.0 format
) (coerce -
0.0 format
)) (coerce -
0.0 format
)))
527 (assert (eq (sb-xc:-
(coerce 0 format
)) (coerce -
0.0 format
)))
528 (assert (eq (sb-xc:-
(coerce -
0.0 format
)) (coerce 0 format
)))
529 (assert (eq (coerce single-float-positive-infinity format
)
530 (sb-xc:-
(coerce single-float-negative-infinity format
))))
531 (assert (eq (coerce single-float-negative-infinity format
)
532 (sb-xc:-
(coerce single-float-positive-infinity format
))))
533 (assert (eq (sb-xc:-
(coerce 0 format
) (coerce 0 format
)) (coerce 0 format
)))
534 (assert (eq (sb-xc:-
(coerce 0 format
) (coerce -
0.0 format
)) (coerce 0 format
)))
535 (assert (eq (sb-xc:-
(coerce -
0.0 format
) (coerce 0 format
)) (coerce -
0.0 format
)))
536 (assert (eq (sb-xc:-
(coerce -
0.0 format
) (coerce -
0.0 format
)) (coerce 0 format
)))
537 (assert (eq (sb-xc:* (coerce 0 format
) (coerce 0 format
)) (coerce 0 format
)))
538 (assert (eq (sb-xc:* (coerce -
0.0 format
) (coerce 0 format
)) (coerce -
0.0 format
)))
539 (assert (eq (sb-xc:* (coerce 0 format
) (coerce -
0.0 format
)) (coerce -
0.0 format
)))
540 (assert (eq (sb-xc:* (coerce -
0.0 format
) (coerce -
0.0 format
)) (coerce 0 format
)))
541 (assert (eq (sb-xc:/ (coerce -
0.0 format
) (coerce -
1 format
)) (coerce 0 format
)))
542 (assert (eq (sb-xc:/ (coerce -
0.0 format
) (coerce 1 format
)) (coerce -
0.0 format
)))
543 (assert (eq (sb-xc:/ (coerce 0 format
) (coerce -
1 format
)) (coerce -
0.0 format
)))
544 (assert (eq (sb-xc:/ (coerce 0 format
) (coerce 1 format
)) (coerce 0 format
)))
545 (assert (eq (sb-xc:fceiling -
1/2) -
0.0f0
))
546 (assert (eq (sb-xc:fceiling
(coerce -
1/2 format
)) (coerce -
0.0 format
)))
547 (assert (eq (sb-xc:ffloor -
1/2) (coerce -
1 'single-float
)))
548 (assert (eq (sb-xc:ffloor
(coerce -
1/2 format
)) (coerce -
1 format
)))
549 (assert (eq (sb-xc:ftruncate -
1/2) -
0.0f0
))
550 (assert (eq (sb-xc:ftruncate
(coerce -
1/2 format
)) (coerce -
0.0 format
)))
551 (assert (eq (sb-xc:fround -
1/2) -
0.0f0
))
552 (assert (eq (sb-xc:fround
(coerce -
1/2 format
)) (coerce -
0.0 format
)))
553 (assert (equal (multiple-value-list (sb-xc:integer-decode-float
1.0f0
))
555 (assert (equal (multiple-value-list (sb-xc:integer-decode-float
1.0d0
))
556 '(4503599627370496 -
52 1)))
557 (let ((*break-on-signals
* nil
))
558 (flet ((assert-not-number (x)
559 (handler-case (rational x
)
560 (:no-error
(x) (error "Expected an error, got ~S" x
))
561 (simple-error (x) (declare (ignore x
))))))
562 (let ((nan (make-single-float #b01111111101000000000000000000000
)))
564 (assert-not-number nan
)
565 (assert (float-nan-p nan
))
566 (assert (float-infinity-or-nan-p nan
))
567 (assert (not (float-infinity-p nan
))))
568 (assert-not-number single-float-negative-infinity
)
569 (assert-not-number single-float-positive-infinity
)
570 (assert-not-number double-float-negative-infinity
)
571 (assert-not-number double-float-positive-infinity
))))