;;; Scale a single or double float, calling the correct over/underflow
;;; functions.
(defun scale-single-float (x exp)
- (declare (single-float x) (fixnum exp))
- (let* ((bits (single-float-bits x))
- (old-exp (ldb sb!vm:single-float-exponent-byte bits))
- (new-exp (+ old-exp exp)))
- (cond
- ((zerop x) x)
- ((or (< old-exp sb!vm:single-float-normal-exponent-min)
- (< new-exp sb!vm:single-float-normal-exponent-min))
- (scale-float-maybe-underflow x exp))
- ((or (> old-exp sb!vm:single-float-normal-exponent-max)
- (> new-exp sb!vm:single-float-normal-exponent-max))
- (scale-float-maybe-overflow x exp))
- (t
- (make-single-float (dpb new-exp
- sb!vm:single-float-exponent-byte
- bits))))))
+ (declare (single-float x) (integer exp))
+ (etypecase exp
+ (fixnum
+ (let* ((bits (single-float-bits x))
+ (old-exp (ldb sb!vm:single-float-exponent-byte bits))
+ (new-exp (+ old-exp exp)))
+ (cond
+ ((zerop x) x)
+ ((or (< old-exp sb!vm:single-float-normal-exponent-min)
+ (< new-exp sb!vm:single-float-normal-exponent-min))
+ (scale-float-maybe-underflow x exp))
+ ((or (> old-exp sb!vm:single-float-normal-exponent-max)
+ (> new-exp sb!vm:single-float-normal-exponent-max))
+ (scale-float-maybe-overflow x exp))
+ (t
+ (make-single-float (dpb new-exp
+ sb!vm:single-float-exponent-byte
+ bits))))))
+ (unsigned-byte (scale-float-maybe-overflow x exp))
+ ((integer * 0) (scale-float-maybe-underflow x exp))))
(defun scale-double-float (x exp)
- (declare (double-float x) (fixnum exp))
- (let* ((hi (double-float-high-bits x))
- (lo (double-float-low-bits x))
- (old-exp (ldb sb!vm:double-float-exponent-byte hi))
- (new-exp (+ old-exp exp)))
- (cond
- ((zerop x) x)
- ((or (< old-exp sb!vm:double-float-normal-exponent-min)
- (< new-exp sb!vm:double-float-normal-exponent-min))
- (scale-float-maybe-underflow x exp))
- ((or (> old-exp sb!vm:double-float-normal-exponent-max)
- (> new-exp sb!vm:double-float-normal-exponent-max))
- (scale-float-maybe-overflow x exp))
- (t
- (make-double-float (dpb new-exp sb!vm:double-float-exponent-byte hi)
- lo)))))
+ (declare (double-float x) (integer exp))
+ (etypecase exp
+ (fixnum
+ (let* ((hi (double-float-high-bits x))
+ (lo (double-float-low-bits x))
+ (old-exp (ldb sb!vm:double-float-exponent-byte hi))
+ (new-exp (+ old-exp exp)))
+ (cond
+ ((zerop x) x)
+ ((or (< old-exp sb!vm:double-float-normal-exponent-min)
+ (< new-exp sb!vm:double-float-normal-exponent-min))
+ (scale-float-maybe-underflow x exp))
+ ((or (> old-exp sb!vm:double-float-normal-exponent-max)
+ (> new-exp sb!vm:double-float-normal-exponent-max))
+ (scale-float-maybe-overflow x exp))
+ (t
+ (make-double-float (dpb new-exp sb!vm:double-float-exponent-byte hi)
+ lo)))))
+ (unsigned-byte (scale-float-maybe-overflow x exp))
+ ((integer * 0) (scale-float-maybe-underflow x exp))))
#!+(and x86 long-float)
(defun scale-long-float (x exp)
- (declare (long-float x) (fixnum exp))
+ (declare (long-float x) (integer exp))
(scale-float x exp))
;;; Dispatch to the correct type-specific scale-float function.
(when (subtypep 'single-float 'short-float)
(assert (eql least-positive-single-float least-positive-short-float)))
-#+nil ; bug 269
-(let ((f (eval 'least-positive-double-float)))
- (assert (eql (multiple-value-bind (signif expon sign)
- (integer-decode-float f)
- (scale-float (float signif f) expon))
- f)))
-
;;; bug found by Paul Dietz: FFLOOR and similar did not work for integers
(let ((tests '(((ffloor -8 3) (-3.0 1))
((fround -8 3) (-3.0 1))
;;; bug found by Paul Dietz: bad rounding on small floats
(assert (= (fround least-positive-short-float least-positive-short-float) 1.0))
+
+;;; bug found by Peter Seibel: scale-float was only accepting float
+;;; exponents, when it should accept all integers. (also bug #269)
+(assert (= (multiple-value-bind (significand expt sign)
+ (integer-decode-float least-positive-double-float)
+ (* (scale-float (float significand 0.0d0) expt) sign))
+ least-positive-double-float))
+(assert (= (multiple-value-bind (significand expt sign)
+ (decode-float least-positive-double-float)
+ (* (scale-float significand expt) sign))
+ least-positive-double-float))
+(assert (= 0.0 (scale-float 1.0 most-negative-fixnum)))
+(assert (= 0.0d0 (scale-float 1.0d0 (1- most-negative-fixnum))))
+(assert (raises-error? (scale-float 1.0 most-positive-fixnum)
+ floating-point-overflow))
+(assert (raises-error? (scale-float 1.0d0 (1+ most-positive-fixnum))
+ floating-point-overflow))