Raymond Toy pushed to branch master at cmucl / cmucl

Commits:

3 changed files:

Changes:

  • src/code/float.lisp
    ... ... @@ -885,40 +885,57 @@
    885 885
     ;;; denormalized or underflows to 0.
    
    886 886
     ;;;
    
    887 887
     (defun scale-float-maybe-underflow (x exp)
    
    888
    -  (multiple-value-bind (sig old-exp)
    
    889
    -		       (integer-decode-float x)
    
    888
    +  (declare (type (or single-float double-float) x)
    
    889
    +	   (fixnum exp))
    
    890
    +  (multiple-value-bind (sig old-exp float-sign)
    
    891
    +      (integer-decode-float x)
    
    890 892
         (let* ((digits (float-digits x))
    
    893
    +	   (1+digits (1+ digits))
    
    891 894
     	   (new-exp (+ exp old-exp digits
    
    892 895
     		       (etypecase x
    
    893 896
     			 (single-float vm:single-float-bias)
    
    894 897
     			 (double-float vm:double-float-bias))))
    
    895
    -	   (sign (if (minusp (float-sign x)) 1 0)))
    
    898
    +	   (sign (if (minusp float-sign) 1 0)))
    
    896 899
           (cond
    
    897
    -       ((< new-exp
    
    898
    -	   (etypecase x
    
    899
    -	     (single-float vm:single-float-normal-exponent-min)
    
    900
    -	     (double-float vm:double-float-normal-exponent-min)))
    
    901
    -	(when (vm:current-float-trap :inexact)
    
    902
    -	  (error 'floating-point-inexact :operation 'scale-float
    
    903
    -		 :operands (list x exp)))
    
    904
    -	(when (vm:current-float-trap :underflow)
    
    905
    -	  (error 'floating-point-underflow :operation 'scale-float
    
    906
    -		 :operands (list x exp)))
    
    907
    -	(let ((shift (1- new-exp)))
    
    908
    -	  ;; Is it necessary to have this IF here?  Is there any case
    
    909
    -	  ;; where (ash sig shift) won't return 0 when
    
    910
    -	  ;; shift < -(digits-1)?
    
    911
    -	  (if (< shift (- (1- digits)))
    
    900
    +	((< new-exp
    
    901
    +	    (etypecase x
    
    902
    +	      (single-float vm:single-float-normal-exponent-min)
    
    903
    +	      (double-float vm:double-float-normal-exponent-min)))
    
    904
    +	 (when (vm:current-float-trap :inexact)
    
    905
    +	   (error 'floating-point-inexact :operation 'scale-float
    
    906
    +		  :operands (list x exp)))
    
    907
    +	 (when (vm:current-float-trap :underflow)
    
    908
    +	   (error 'floating-point-underflow :operation 'scale-float
    
    909
    +		  :operands (list x exp)))
    
    910
    +	 ;; To round correctly, let the hardware multiplier do the
    
    911
    +	 ;; rounding: build a normal float whose stored exponent is
    
    912
    +	 ;; bumped up by 1+DIGITS (which puts it safely in the normal
    
    913
    +	 ;; range), then multiply by 2^-(1+DIGITS).  The multiplier is
    
    914
    +	 ;; an exact power of two, so the multiplication is exact
    
    915
    +	 ;; apart from the unavoidable rounding step that expresses
    
    916
    +	 ;; the product as a denormal, which the FPU performs in the
    
    917
    +	 ;; current rounding mode.  If the bumped exponent is zero or
    
    918
    +	 ;; negative the bumped float would itself be a denormal --
    
    919
    +	 ;; losing the implicit 1 bit of SIG -- so handle that case
    
    920
    +	 ;; explicitly by returning signed zero.
    
    921
    +	 (let ((bumped-exp (+ new-exp 1+digits)))
    
    922
    +	   (cond
    
    923
    +	     ((<= bumped-exp 0)
    
    912 924
     	      (etypecase x
    
    913 925
     		(single-float (single-from-bits sign 0 0))
    
    914
    -		(double-float (double-from-bits sign 0 0)))
    
    926
    +		(double-float (double-from-bits sign 0 0))))
    
    927
    +	     (t
    
    915 928
     	      (etypecase x
    
    916
    -		(single-float (single-from-bits sign 0 (ash sig shift)))
    
    917
    -		(double-float (double-from-bits sign 0 (ash sig shift)))))))
    
    918
    -       (t
    
    919
    -	(etypecase x
    
    920
    -	  (single-float (single-from-bits sign new-exp sig))
    
    921
    -	  (double-float (double-from-bits sign new-exp sig))))))))
    
    929
    +		(single-float
    
    930
    +		 (* (single-from-bits sign bumped-exp sig)
    
    931
    +		    (scale-float 1f0 (- 1+digits))))
    
    932
    +		(double-float
    
    933
    +		 (* (double-from-bits sign bumped-exp sig)
    
    934
    +		    (scale-float 1d0 (- 1+digits)))))))))
    
    935
    +	(t
    
    936
    +	 (etypecase x
    
    937
    +	   (single-float (single-from-bits sign new-exp sig))
    
    938
    +	   (double-float (double-from-bits sign new-exp sig))))))))
    
    922 939
     
    
    923 940
     
    
    924 941
     ;;; SCALE-FLOAT-MAYBE-OVERFLOW  --  Internal
    
    ... ... @@ -1135,42 +1152,74 @@
    1135 1152
     			  (assert (= len (the fixnum (1+ digits))))
    
    1136 1153
     			  (multiple-value-bind (f0)
    
    1137 1154
     			      (floatit (ash bits -1))
    
    1138
    -			    #+nil
    
    1139
    -			    (progn
    
    1140
    -                              (format t "x = ~A~%" x)
    
    1141
    -			      (format t "1: f0, f1 = ~A~%" f0)
    
    1142
    -			      (format t "   scale = ~A~%" (1+ scale)))
    
    1143
    -			    
    
    1144 1155
     			    (scale-float f0 (1+ scale))))
    
    1145 1156
     			 (t
    
    1146 1157
     			  (multiple-value-bind (f0)
    
    1147 1158
     			      (floatit bits)
    
    1148
    -			    #+nil
    
    1149
    -			    (progn
    
    1150
    -			      (format t "2: f0, f1 = ~A~%" f0)
    
    1151
    -			      (format t "   scale = ~A~%" scale)
    
    1152
    -			      (format t "scale-float f0 = ~A~%" (scale-float f0 scale)))
    
    1153
    -                            (let ((min-exponent
    
    1154
    -                                    ;; Compute the min (unbiased) exponent
    
    1155
    -                                    (ecase format
    
    1156
    -                                      (single-float
    
    1157
    -                                       (- vm:single-float-normal-exponent-min
    
    1158
    -                                          vm:single-float-bias
    
    1159
    -                                          vm:single-float-digits))
    
    1160
    -                                      (double-float
    
    1161
    -                                       (- vm:double-float-normal-exponent-min
    
    1162
    -                                          vm:double-float-bias
    
    1163
    -                                          vm:double-float-digits)))))
    
    1164
    -                              ;; F0 is always between 0.5 and 1.  If
    
    1165
    -                              ;; SCALE is the min exponent, we have a
    
    1166
    -                              ;; denormal number just less than the
    
    1167
    -                              ;; least-positive float.  We want to
    
    1168
    -                              ;; return the least-positive-float so
    
    1169
    -                              ;; multiply F0 by 2 (without adjusting
    
    1170
    -                              ;; SCALE) to get the nearest float.
    
    1171
    -                              (if (= scale min-exponent)
    
    1172
    -                                  (scale-float (* 2 f0) scale)
    
    1173
    -			          (scale-float f0 scale))))))))
    
    1159
    +			    (scale-float f0 scale))))))
    
    1160
    +	       (denormal-excess ()
    
    1161
    +		 ;; How many bits of precision the result loses by being
    
    1162
    +		 ;; denormal instead of normal.  A normal-precision return
    
    1163
    +		 ;; would be BITS*2^(SCALE-DIGITS) with BITS having DIGITS
    
    1164
    +		 ;; bits.  Once it's known that this representation will
    
    1165
    +		 ;; produce a denormal -- equivalently, that SCALE-FLOAT-
    
    1166
    +		 ;; MAYBE-UNDERFLOW would take the underflow branch --
    
    1167
    +		 ;; (1 - BIAS) - SCALE bits of the mantissa fall below the
    
    1168
    +		 ;; denormal's narrower storage and must be rounded off.
    
    1169
    +		 ;; Zero in the normal range.
    
    1170
    +		 (let ((bias
    
    1171
    +			(ecase format
    
    1172
    +			  (single-float vm:single-float-bias)
    
    1173
    +			  (double-float vm:double-float-bias))))
    
    1174
    +		   (declare (fixnum bias))
    
    1175
    +		   (max 0 (the fixnum
    
    1176
    +				(- (the fixnum (- 1 bias))
    
    1177
    +				   scale)))))
    
    1178
    +	       (round-denormal (fraction-and-guard rem excess)
    
    1179
    +		 ;; FRACTION-AND-GUARD has (1+ DIGITS) bits with one guard
    
    1180
    +		 ;; bit; round it to (- DIGITS EXCESS) bits using round-to-
    
    1181
    +		 ;; nearest, ties to even, with REM as the sticky tail.
    
    1182
    +		 ;; Drops EXCESS+1 low bits in a single step.  This is the
    
    1183
    +		 ;; one rounding the denormal result undergoes; no
    
    1184
    +		 ;; subsequent SCALE-FLOAT call is needed, so there is no
    
    1185
    +		 ;; double rounding.
    
    1186
    +		 (declare (type unsigned-byte fraction-and-guard rem)
    
    1187
    +			  (fixnum excess))
    
    1188
    +		 (let* ((shift (1+ excess))
    
    1189
    +			(low (ldb (byte shift 0) fraction-and-guard))
    
    1190
    +			(quot (ash fraction-and-guard (- shift)))
    
    1191
    +			(halfway (ash 1 excess)))
    
    1192
    +		   (declare (fixnum shift))
    
    1193
    +		   (cond ((< low halfway) quot)
    
    1194
    +			 ((> low halfway) (1+ quot))
    
    1195
    +			 ((not (zerop rem)) (1+ quot))
    
    1196
    +			 ((oddp quot) (1+ quot))
    
    1197
    +			 (t quot))))
    
    1198
    +	       (denormal-from-bits (mantissa excess)
    
    1199
    +		 ;; MANTISSA has at most (- DIGITS EXCESS) bits and is the
    
    1200
    +		 ;; stored significand of a denormal result.  Denormal
    
    1201
    +		 ;; storage holds (1- DIGITS) bits, so rounding can carry
    
    1202
    +		 ;; into the smallest normal only when EXCESS = 1, in
    
    1203
    +		 ;; which case MANTISSA can be exactly (ASH 1 (1- DIGITS)).
    
    1204
    +		 (declare (fixnum excess))
    
    1205
    +		 (let ((sign (if plusp 0 1)))
    
    1206
    +		   (case format
    
    1207
    +		     (single-float
    
    1208
    +		      (cond ((and (= excess 1)
    
    1209
    +				  (= mantissa
    
    1210
    +				     (ash 1 (1- vm:single-float-digits))))
    
    1211
    +			     (single-from-bits
    
    1212
    +			      sign vm:single-float-normal-exponent-min 0))
    
    1213
    +			    (t
    
    1214
    +			     (single-from-bits sign 0 mantissa))))
    
    1215
    +		     (double-float
    
    1216
    +		      (cond ((and (= excess 1)
    
    1217
    +				  (= mantissa
    
    1218
    +				     (ash 1 (1- vm:double-float-digits))))
    
    1219
    +			     (double-from-bits
    
    1220
    +			      sign vm:double-float-normal-exponent-min 0))
    
    1221
    +			    (t
    
    1222
    +			     (double-from-bits sign 0 mantissa)))))))
    
    1174 1223
     	       (floatit (bits)
    
    1175 1224
     		 (let ((sign (if plusp 0 1)))
    
    1176 1225
     		   (case format
    
    ... ... @@ -1188,16 +1237,36 @@
    1188 1237
     	      (declare (fixnum extra))
    
    1189 1238
     	      (cond ((/= extra 1)
    
    1190 1239
     		     (assert (> extra 1)))
    
    1191
    -		    ((oddp fraction-and-guard)
    
    1192
    -		     (return
    
    1193
    -		      (if (zerop rem)
    
    1194
    -			  (float-and-scale
    
    1195
    -			   (if (zerop (logand fraction-and-guard 2))
    
    1196
    -			       fraction-and-guard
    
    1197
    -			       (1+ fraction-and-guard)))
    
    1198
    -			  (float-and-scale (1+ fraction-and-guard)))))
    
    1199 1240
     		    (t
    
    1200
    -		     (return (float-and-scale fraction-and-guard)))))
    
    1241
    +		     (return
    
    1242
    +		      (let ((excess (denormal-excess)))
    
    1243
    +			(cond
    
    1244
    +			  ((zerop excess)
    
    1245
    +			   ;; Normal result: original odd/even tie-break.
    
    1246
    +			   (cond ((oddp fraction-and-guard)
    
    1247
    +				  (if (zerop rem)
    
    1248
    +				      (float-and-scale
    
    1249
    +				       (if (zerop
    
    1250
    +					    (logand fraction-and-guard 2))
    
    1251
    +					   fraction-and-guard
    
    1252
    +					   (1+ fraction-and-guard)))
    
    1253
    +				      (float-and-scale
    
    1254
    +				       (1+ fraction-and-guard))))
    
    1255
    +				 (t
    
    1256
    +				  (float-and-scale fraction-and-guard))))
    
    1257
    +			  (t
    
    1258
    +			   ;; Denormal result: re-round directly to the
    
    1259
    +			   ;; denormal's narrower precision so the only
    
    1260
    +			   ;; rounding step happens here.  Rounding to
    
    1261
    +			   ;; DIGITS first and re-rounding via
    
    1262
    +			   ;; SCALE-FLOAT-MAYBE-UNDERFLOW would double-
    
    1263
    +			   ;; round (e.g. 7.290983e-39 would land on an
    
    1264
    +			   ;; artifical tie at the 24-bit boundary).
    
    1265
    +			   (let ((mantissa
    
    1266
    +				  (round-denormal fraction-and-guard rem
    
    1267
    +						  excess)))
    
    1268
    +			     (declare (type unsigned-byte mantissa))
    
    1269
    +			     (denormal-from-bits mantissa excess)))))))))
    
    1201 1270
     	    (setq shifted-num (ash shifted-num -1))
    
    1202 1271
     	    (incf scale)))))))
    
    1203 1272
     
    

  • src/general-info/release-22a.md
    ... ... @@ -58,6 +58,8 @@ public domain.
    58 58
         * #463: `double-double-float` is missing comparison operations
    
    59 59
                 between `double-double-float` and `double-float`
    
    60 60
         * #474: Add functions to print and parse C-style hex floats.
    
    61
    +    * #504: Do correct rounding in `scale-float-maybe-underflow`.
    
    62
    +            This was causing some denormals to be read incorrectly.
    
    61 63
       * Other changes:
    
    62 64
       * Improvements to the PCL implementation of CLOS:
    
    63 65
       * Changes to building procedure:
    

  • tests/float.lisp
    ... ... @@ -179,7 +179,9 @@
    179 179
                         (kernel::float-ratio-float (* 4 expo) 'double-float))
    
    180 180
           (assert-equal least-positive-double-float
    
    181 181
                         (kernel::float-ratio-float (* 494/100 expo) 'double-float))
    
    182
    -      (assert-equal least-positive-double-float
    
    182
    +      ;; 988/100*10^-324 is very close to 2*least-positive (the exact ratio
    
    183
    +      ;; is 1.9997 * least-positive), so it rounds to 2*least-positive.
    
    184
    +      (assert-equal (* 2 least-positive-double-float)
    
    183 185
                         (kernel::float-ratio-float (* 988/100 expo) 'double-float)))))
    
    184 186
         
    
    185 187
     (define-test reader-error.small-single-floats
    
    ... ... @@ -678,8 +680,11 @@
    678 680
       (frob cdiv.maxima-case
    
    679 681
     	#c(5.43d-10 1.13d-100)
    
    680 682
     	#c(1.2d-311 5.7d-312)
    
    681
    -	#c(3.691993880674614517999740937026568563794896024143749539711267954d301
    
    682
    -	   -1.753697093319947872394996242210428954266103103602859195409591583d301)
    
    683
    +	;; Compute the expected value using rational arithmetic after
    
    684
    +	;; converting the complex numbers above to the equivalent
    
    685
    +	;; complex rationals.
    
    686
    +	(/ (complex (rational 5.43d-10) (rational 1.13d-100))
    
    687
    +	   (complex (rational 1.2d-311) (rational 5.7d-312)))
    
    683 688
     	52)
    
    684 689
       ;; 12
    
    685 690
       ;;
    
    ... ... @@ -766,3 +771,258 @@
    766 771
     		     (coerce y '(complex single-float)))
    
    767 772
     		  x
    
    768 773
     		  y)))
    
    774
    +
    
    775
    +(define-test scale-float-underflow-rounding.single
    
    776
    +    (:tag :issues)
    
    777
    +  ;; SCALE-FLOAT into the denormal range must round to nearest, ties to
    
    778
    +  ;; even, instead of truncating the discarded bits.  Each (X EXP BITS)
    
    779
    +  ;; triple gives a normal X, an exponent EXP to scale by, and the IEEE
    
    780
    +  ;; bits of the expected single-float result.
    
    781
    +  (ext:with-float-traps-masked (:underflow :inexact)
    
    782
    +    (dolist (case (list
    
    783
    +                   ;; 1.7f0 * 2^-149: between denormals 1 and 2, closer to 2.
    
    784
    +                   (list 1.7f0  -149 #x00000002)
    
    785
    +                   ;; 1.5f0 * 2^-149: halfway between denormals 1 and 2;
    
    786
    +                   ;; ties round to even -> 2.
    
    787
    +                   (list 1.5f0  -149 #x00000002)
    
    788
    +                   ;; 1.1f0 * 2^-149: closer to denormal 1.
    
    789
    +                   (list 1.1f0  -149 #x00000001)
    
    790
    +                   ;; 1.0001f0 * 2^-150: just above halfway between 0 and
    
    791
    +                   ;; smallest denormal; rounds up to 1.
    
    792
    +                   (list 1.0001f0 -150 #x00000001)
    
    793
    +                   ;; 1.0f0 * 2^-150: exactly halfway between 0 and smallest
    
    794
    +                   ;; denormal; ties round to even -> 0.
    
    795
    +                   (list 1.0f0  -150 #x00000000)
    
    796
    +                   ;; Largest single < 2 scaled by 2^-127: rounding carries
    
    797
    +                   ;; into the implicit-1 position and produces the smallest
    
    798
    +                   ;; normal number.
    
    799
    +                   (list (kernel:make-single-float #x3fffffff)
    
    800
    +                         -127 #x00800000)))
    
    801
    +      (destructuring-bind (x exp bits) case
    
    802
    +        (let ((result (scale-float x exp)))
    
    803
    +          (assert-equal bits (kernel:single-float-bits result)
    
    804
    +                        x exp result))))))
    
    805
    +
    
    806
    +(define-test scale-float-underflow-rounding.double
    
    807
    +    (:tag :issues)
    
    808
    +  ;; Like SCALE-FLOAT-UNDERFLOW-ROUNDING.SINGLE but for double-floats.
    
    809
    +  ;; Each (X EXP HI LO) gives a normal X, an exponent EXP, and the IEEE
    
    810
    +  ;; high and low bits of the expected double-float result.
    
    811
    +  (ext:with-float-traps-masked (:underflow :inexact)
    
    812
    +    (dolist (case (list
    
    813
    +                   ;; 1.7d0 * 2^-1074: between denormals 1 and 2, closer to 2.
    
    814
    +                   (list 1.7d0  -1074 0 2)
    
    815
    +                   ;; 1.5d0 * 2^-1074: tie, rounds to even -> 2.
    
    816
    +                   (list 1.5d0  -1074 0 2)
    
    817
    +                   ;; 1.1d0 * 2^-1074: closer to denormal 1.
    
    818
    +                   (list 1.1d0  -1074 0 1)
    
    819
    +                   ;; 1.0001d0 * 2^-1075: just above halfway, rounds up.
    
    820
    +                   (list 1.0001d0 -1075 0 1)
    
    821
    +                   ;; 1.0d0 * 2^-1075: tie at the bottom, rounds to even -> 0.
    
    822
    +                   (list 1.0d0  -1075 0 0)
    
    823
    +                   ;; Largest double < 2 scaled by 2^-1023: rounding carries
    
    824
    +                   ;; into the implicit-1 position and produces the smallest
    
    825
    +                   ;; normal number.
    
    826
    +                   (list (kernel:make-double-float #x3fffffff #xffffffff)
    
    827
    +                         -1023 #x00100000 0)))
    
    828
    +      (destructuring-bind (x exp hi lo) case
    
    829
    +        (let ((result (scale-float x exp)))
    
    830
    +          (assert-equal hi (kernel:double-float-high-bits result)
    
    831
    +                        x exp result)
    
    832
    +          (assert-equal lo (kernel:double-float-low-bits result)
    
    833
    +                        x exp result))))))
    
    834
    +
    
    835
    +(define-test scale-float-underflow-rounding.reader-single
    
    836
    +    (:tag :issues)
    
    837
    +  ;; The reader uses FLOAT-RATIO-FLOAT, which calls SCALE-FLOAT and
    
    838
    +  ;; hence SCALE-FLOAT-MAYBE-UNDERFLOW on denormal results.  Reading
    
    839
    +  ;; small float literals must therefore also round to nearest.
    
    840
    +  (ext:with-float-traps-masked (:underflow :inexact)
    
    841
    +    ;; 1.1e-44 is closer to 8 * least-positive-single-float than to 7.
    
    842
    +    (assert-equal #x00000008
    
    843
    +                  (kernel:single-float-bits 1.1e-44))
    
    844
    +    ;; 1.121e-44 (essentially the IEEE representation of 1.1e-44) reads
    
    845
    +    ;; as the same denormal.
    
    846
    +    (assert-equal #x00000008
    
    847
    +                  (kernel:single-float-bits 1.121e-44))))
    
    848
    +
    
    849
    +(define-test scale-float-underflow-rounding.reader-double
    
    850
    +    (:tag :issues)
    
    851
    +  ;; Like the single-float reader test, in the double denormal range.
    
    852
    +  ;; 1.1d-322 is closest to denormal #x16 (= 22).
    
    853
    +  (ext:with-float-traps-masked (:underflow :inexact)
    
    854
    +    (assert-equal 0 (kernel:double-float-high-bits 1.1d-322))
    
    855
    +    (assert-equal #x16 (kernel:double-float-low-bits 1.1d-322))))
    
    856
    +
    
    857
    +(define-test float-ratio-float.denormal-double-rounding.single
    
    858
    +    (:tag :issues)
    
    859
    +  ;; Regression for the double-rounding bug exposed by reading
    
    860
    +  ;; "7.290983e-39".  The exact rational lies at 5203019.332 * 2^-149,
    
    861
    +  ;; below halfway between denormals #x4f644b and #x4f644c.  An earlier
    
    862
    +  ;; fix rounded to 24 bits first (lifting it to the artificial tie
    
    863
    +  ;; 5203019.5 * 2^-149) and then re-rounded ties-to-even to #x4f644c.
    
    864
    +  ;; FLOAT-RATIO-FLOAT now re-rounds directly to denormal precision in a
    
    865
    +  ;; single step, yielding the correctly-rounded #x4f644b.
    
    866
    +  (assert-equal #x4f644b
    
    867
    +		(kernel:single-float-bits 7.290983e-39)))
    
    868
    +
    
    869
    +(define-test float-ratio-float.denormal-low-below-halfway.single
    
    870
    +    (:tag :issues)
    
    871
    +  ;; Exercise ROUND-DENORMAL's `low < halfway' branch via FLOAT-RATIO-
    
    872
    +  ;; FLOAT.  Value 11/10 * least-positive is 1.1 denormal-units; the
    
    873
    +  ;; loop sees several bits of low and the comparison must take the
    
    874
    +  ;; round-down path so the mantissa stays at 1.
    
    875
    +  (let ((x (* 11/10 (expt 2 -149))))
    
    876
    +    (assert-equal #x00000001
    
    877
    +		  (kernel:single-float-bits
    
    878
    +		   (kernel::float-ratio-float x 'single-float))
    
    879
    +		  x)))
    
    880
    +
    
    881
    +(define-test float-ratio-float.denormal-low-above-halfway.single
    
    882
    +    (:tag :issues)
    
    883
    +  ;; ROUND-DENORMAL's `low > halfway' branch: 17/10 * least-positive
    
    884
    +  ;; (= 1.7 denormal-units), past halfway between 1 and 2, rounds up.
    
    885
    +  (let ((x (* 17/10 (expt 2 -149))))
    
    886
    +    (assert-equal #x00000002
    
    887
    +		  (kernel:single-float-bits
    
    888
    +		   (kernel::float-ratio-float x 'single-float))
    
    889
    +		  x)))
    
    890
    +
    
    891
    +(define-test float-ratio-float.denormal-tie-to-even.single
    
    892
    +    (:tag :issues)
    
    893
    +  ;; ROUND-DENORMAL's tie path, REM = 0: exact halfway between two
    
    894
    +  ;; denormals rounds to even.  3/2 * least-positive ties between
    
    895
    +  ;; denormals 1 and 2; the even neighbour is 2.
    
    896
    +  (let ((x (* 3/2 (expt 2 -149))))
    
    897
    +    (assert-equal #x00000002
    
    898
    +		  (kernel:single-float-bits
    
    899
    +		   (kernel::float-ratio-float x 'single-float))
    
    900
    +		  x))
    
    901
    +  ;; 5/2 * least-positive ties between 2 and 3; even is 2.
    
    902
    +  (let ((x (* 5/2 (expt 2 -149))))
    
    903
    +    (assert-equal #x00000002
    
    904
    +		  (kernel:single-float-bits
    
    905
    +		   (kernel::float-ratio-float x 'single-float))
    
    906
    +		  x))
    
    907
    +  ;; 7/2 * least-positive ties between 3 and 4; even is 4.
    
    908
    +  (let ((x (* 7/2 (expt 2 -149))))
    
    909
    +    (assert-equal #x00000004
    
    910
    +		  (kernel:single-float-bits
    
    911
    +		   (kernel::float-ratio-float x 'single-float))
    
    912
    +		  x))
    
    913
    +  ;; 1/2 * least-positive ties between 0 and 1; even is 0.
    
    914
    +  (let ((x (* 1/2 (expt 2 -149))))
    
    915
    +    (assert-equal #x00000000
    
    916
    +		  (kernel:single-float-bits
    
    917
    +		   (kernel::float-ratio-float x 'single-float))
    
    918
    +		  x)))
    
    919
    +
    
    920
    +(define-test float-ratio-float.denormal-tie-with-sticky.single
    
    921
    +    (:tag :issues)
    
    922
    +  ;; ROUND-DENORMAL's tie path with REM != 0: when the loop's
    
    923
    +  ;; FRACTION-AND-GUARD reaches an exact halfway pattern but the
    
    924
    +  ;; division has a nonzero remainder, the rounding must go up because
    
    925
    +  ;; the original rational is strictly above halfway.  3/2 * least-
    
    926
    +  ;; positive + a tiny fraction of least-positive lands just past tie 1-2,
    
    927
    +  ;; rounds up to 2.
    
    928
    +  (let ((x (+ (* 3/2 (expt 2 -149))
    
    929
    +	      (* (expt 2 -149) 1/1000000000))))
    
    930
    +    (assert-equal #x00000002
    
    931
    +		  (kernel:single-float-bits
    
    932
    +		   (kernel::float-ratio-float x 'single-float))
    
    933
    +		  x))
    
    934
    +  ;; 1/2 + tiny: just past tie 0-1, rounds up to 1.
    
    935
    +  (let ((x (+ (* 1/2 (expt 2 -149))
    
    936
    +	      (* (expt 2 -149) 1/1000000000))))
    
    937
    +    (assert-equal #x00000001
    
    938
    +		  (kernel:single-float-bits
    
    939
    +		   (kernel::float-ratio-float x 'single-float))
    
    940
    +		  x)))
    
    941
    +
    
    942
    +(define-test float-ratio-float.denormal-excess.single
    
    943
    +    (:tag :issues)
    
    944
    +  ;; Exercise DENORMAL-EXCESS over a range of magnitudes.  EXCESS
    
    945
    +  ;; varies inversely with the result's magnitude; each case has the
    
    946
    +  ;; result land on a chosen denormal so an off-by-one in the EXCESS
    
    947
    +  ;; computation would shift the result by a factor of two.
    
    948
    +  ;; EXCESS = 1: value near smallest normal; pick (2^23 - 1) * 2^-149,
    
    949
    +  ;; the largest denormal.
    
    950
    +  (let ((x (* (1- (expt 2 23)) (expt 2 -149))))
    
    951
    +    (assert-equal #x007fffff
    
    952
    +		  (kernel:single-float-bits
    
    953
    +		   (kernel::float-ratio-float x 'single-float))
    
    954
    +		  x))
    
    955
    +  ;; EXCESS = 4: small denormal, mantissa 2^19.
    
    956
    +  (let ((x (expt 2 -130)))
    
    957
    +    (assert-equal (ash 1 19)
    
    958
    +		  (kernel:single-float-bits
    
    959
    +		   (kernel::float-ratio-float x 'single-float))
    
    960
    +		  x))
    
    961
    +  ;; EXCESS = 21: very small denormal, mantissa 8.
    
    962
    +  (let ((x (* 8 (expt 2 -149))))
    
    963
    +    (assert-equal #x00000008
    
    964
    +		  (kernel:single-float-bits
    
    965
    +		   (kernel::float-ratio-float x 'single-float))
    
    966
    +		  x))
    
    967
    +  ;; EXCESS = 23 (the maximum): only the bottom three denormals are
    
    968
    +  ;; reachable.  3 * least-positive gives mantissa 3.
    
    969
    +  (let ((x (* 3 (expt 2 -149))))
    
    970
    +    (assert-equal #x00000003
    
    971
    +		  (kernel:single-float-bits
    
    972
    +		   (kernel::float-ratio-float x 'single-float))
    
    973
    +		  x)))
    
    974
    +
    
    975
    +(define-test float-ratio-float.denormal-carry-to-normal.single
    
    976
    +    (:tag :issues)
    
    977
    +  ;; DENORMAL-FROM-BITS's carry-into-smallest-normal branch.  Rounding
    
    978
    +  ;; promotes the denormal mantissa to 2^(DIGITS-1), which doesn't fit
    
    979
    +  ;; in the denormal's stored mantissa width; the result must be the
    
    980
    +  ;; smallest normal (stored exponent = 1, mantissa = 0).
    
    981
    +  ;;
    
    982
    +  ;; (2^24 - 1)/2 * 2^-149 is an exact tie between the largest denormal
    
    983
    +  ;; (mantissa 2^23 - 1) and the smallest normal (2^-126); the latter
    
    984
    +  ;; has stored mantissa 0 which is even, so the tie rounds to it.
    
    985
    +  (let ((x (* (1- (expt 2 24)) 1/2 (expt 2 -149))))
    
    986
    +    (assert-equal #x00800000
    
    987
    +		  (kernel:single-float-bits
    
    988
    +		   (kernel::float-ratio-float x 'single-float))
    
    989
    +		  x))
    
    990
    +  ;; Just past that tie, also rounds up to smallest normal.
    
    991
    +  (let ((x (+ (* (1- (expt 2 24)) 1/2 (expt 2 -149))
    
    992
    +	      (* (expt 2 -149) 1/1000))))
    
    993
    +    (assert-equal #x00800000
    
    994
    +		  (kernel:single-float-bits
    
    995
    +		   (kernel::float-ratio-float x 'single-float))
    
    996
    +		  x))
    
    997
    +  ;; Just below that tie, rounds down to the largest denormal.
    
    998
    +  (let ((x (- (* (1- (expt 2 24)) 1/2 (expt 2 -149))
    
    999
    +	      (* (expt 2 -149) 1/1000))))
    
    1000
    +    (assert-equal #x007fffff
    
    1001
    +		  (kernel:single-float-bits
    
    1002
    +		   (kernel::float-ratio-float x 'single-float))
    
    1003
    +		  x)))
    
    1004
    +
    
    1005
    +(define-test float-ratio-float.denormal-double-rounding.double
    
    1006
    +    (:tag :issues)
    
    1007
    +  ;; Double-float equivalents.  Pick a rational that lands strictly
    
    1008
    +  ;; below halfway between two denormals after 53-bit rounding would
    
    1009
    +  ;; otherwise lift to the halfway position.  Verify a few denormal
    
    1010
    +  ;; cases also work end-to-end through FLOAT-RATIO-FLOAT.
    
    1011
    +  ;;
    
    1012
    +  ;; 1.1d-322 -> mantissa #x16 (= 22).
    
    1013
    +  (assert-equal 0 (kernel:double-float-high-bits 1.1d-322))
    
    1014
    +  (assert-equal #x16 (kernel:double-float-low-bits 1.1d-322))
    
    1015
    +  ;; Tie-to-even, double: 3/2 * least-positive ties between denormals
    
    1016
    +  ;; 1 and 2; even neighbour is 2.
    
    1017
    +  (let ((x (* 3/2 (expt 2 -1074))))
    
    1018
    +    (assert-equal 0 (kernel:double-float-high-bits
    
    1019
    +		     (kernel::float-ratio-float x 'double-float)))
    
    1020
    +    (assert-equal 2 (kernel:double-float-low-bits
    
    1021
    +		     (kernel::float-ratio-float x 'double-float))))
    
    1022
    +  ;; Carry into smallest normal: (2^53 - 1)/2 * 2^-1074 exactly halfway
    
    1023
    +  ;; between the largest double denormal and the smallest normal;
    
    1024
    +  ;; rounds up to the smallest normal #x00100000_00000000.
    
    1025
    +  (let* ((x (* (1- (expt 2 53)) 1/2 (expt 2 -1074)))
    
    1026
    +	 (r (kernel::float-ratio-float x 'double-float)))
    
    1027
    +    (assert-equal #x00100000 (kernel:double-float-high-bits r) x)
    
    1028
    +    (assert-equal 0 (kernel:double-float-low-bits r) x)))