CLOS classes has had redundant type checks removed.
* optimization: added declarations to speed up operations that access
the internal character database (for example STRING-UPCASE)
+ * optimization: comparison operations between floats and sufficiently small
+ fixnums no longer create extra rationals
* fixed some bugs related to Unicode integration:
** portions of multibyte characters at the end of buffers for
character-based file input are correctly transferred to the
(declare (type real number result))
(if (< (car nlist) result) (setq result (car nlist)))))
+(defconstant most-positive-exactly-single-float-fixnum
+ (min #xffffff most-positive-fixnum))
+(defconstant most-negative-exactly-single-float-fixnum
+ (max #x-ffffff most-negative-fixnum))
+(defconstant most-positive-exactly-double-float-fixnum
+ (min #x1fffffffffffff most-positive-fixnum))
+(defconstant most-negative-exactly-double-float-fixnum
+ (max #x-1fffffffffffff most-negative-fixnum))
+
(eval-when (:compile-toplevel :execute)
;;; The INFINITE-X-FINITE-Y and INFINITE-Y-FINITE-X args tell us how
#!+long-float
((long-float (foreach single-float double-float))
(,op x (coerce y 'long-float)))
+ ((fixnum (foreach single-float double-float))
+ (if (float-infinity-p y)
+ ,infinite-y-finite-x
+ ;; If the fixnum has an exact float representation, do a
+ ;; float comparison. Otherwise do the slow float -> ratio
+ ;; conversion.
+ (multiple-value-bind (lo hi)
+ (case '(dispatch-type y)
+ ('single-float
+ (values most-negative-exactly-single-float-fixnum
+ most-positive-exactly-single-float-fixnum))
+ ('double-float
+ (values most-negative-exactly-double-float-fixnum
+ most-positive-exactly-double-float-fixnum)))
+ (if (<= lo y hi)
+ (,op (coerce x '(dispatch-type y)) y)
+ (,op x (rational y))))))
+ (((foreach single-float double-float) fixnum)
+ (if (eql y 0)
+ (,op x (coerce 0 '(dispatch-type x)))
+ (if (float-infinity-p x)
+ ,infinite-x-finite-y
+ ;; Likewise
+ (multiple-value-bind (lo hi)
+ (case '(dispatch-type x)
+ ('single-float
+ (values most-negative-exactly-single-float-fixnum
+ most-positive-exactly-single-float-fixnum))
+ ('double-float
+ (values most-negative-exactly-double-float-fixnum
+ most-positive-exactly-double-float-fixnum)))
+ (if (<= lo y hi)
+ (,op x (coerce y '(dispatch-type x)))
+ (,op (rational x) y))))))
(((foreach single-float double-float) double-float)
(,op (coerce x 'double-float) y))
((double-float single-float)
(frob /)
(frob floor)
(frob ceiling))
+
+;; Check that the logic in SB-KERNEL::BASIC-COMPARE for doing fixnum/float
+;; comparisons without rationalizing the floats still gives the right anwers
+;; in the edge cases (had a fencepost error).
+(macrolet ((test (range type sign)
+ `(let (ints
+ floats
+ (start (- ,(find-symbol (format nil
+ "MOST-~A-EXACTLY-~A-FIXNUM"
+ sign type)
+ :sb-kernel)
+ ,range)))
+ (dotimes (i (1+ (* ,range 2)))
+ (let* ((x (+ start i))
+ (y (coerce x ',type)))
+ (push x ints)
+ (push y floats)))
+ (dolist (i ints)
+ (dolist (f floats)
+ (dolist (op '(< <= = >= >))
+ (unless (eq (funcall op i f)
+ (funcall op i (rationalize f)))
+ (error "(not (eq (~a ~a ~f) (~a ~a ~a)))~%"
+ op i f
+ op i (rationalize f)))
+ (unless (eq (funcall op f i)
+ (funcall op (rationalize f) i))
+ (error "(not (eq (~a ~f ~a) (~a ~a ~a)))~%"
+ op f i
+ op (rationalize f) i))))))))
+ (test 32 double-float negative)
+ (test 32 double-float positive)
+ (test 32 single-float negative)
+ (test 32 single-float positive))