@@ -16,7 +16,7 @@ mod random;
16
16
pub fn decode_finite < T : DecodableFloat > ( v : T ) -> Decoded {
17
17
match decode ( v) . 1 {
18
18
FullDecoded :: Finite ( decoded) => decoded,
19
- full_decoded => panic ! ( "expected finite, got {full_decoded:?} instead" ) ,
19
+ full_decoded => panic ! ( "expected finite, got {full_decoded:?} instead for {v:?} " ) ,
20
20
}
21
21
}
22
22
@@ -75,6 +75,11 @@ macro_rules! try_fixed {
75
75
} )
76
76
}
77
77
78
+ #[ cfg( target_has_reliable_f16) ]
79
+ fn ldexp_f16 ( a : f16 , b : i32 ) -> f16 {
80
+ ldexp_f64 ( a as f64 , b) as f16
81
+ }
82
+
78
83
fn ldexp_f32 ( a : f32 , b : i32 ) -> f32 {
79
84
ldexp_f64 ( a as f64 , b) as f32
80
85
}
@@ -176,6 +181,13 @@ trait TestableFloat: DecodableFloat + fmt::Display {
176
181
fn ldexpi ( f : i64 , exp : isize ) -> Self ;
177
182
}
178
183
184
+ #[ cfg( target_has_reliable_f16) ]
185
+ impl TestableFloat for f16 {
186
+ fn ldexpi ( f : i64 , exp : isize ) -> Self {
187
+ f as Self * ( exp as Self ) . exp2 ( )
188
+ }
189
+ }
190
+
179
191
impl TestableFloat for f32 {
180
192
fn ldexpi ( f : i64 , exp : isize ) -> Self {
181
193
f as Self * ( exp as Self ) . exp2 ( )
@@ -225,6 +237,76 @@ macro_rules! check_exact_one {
225
237
//
226
238
// [1] Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion
227
239
// ftp://ftp.ee.lbl.gov/testbase-report.ps.Z
240
+ // or https://www.icir.org/vern/papers/testbase-report.pdf
241
+
242
+ #[ cfg( target_has_reliable_f16) ]
243
+ pub fn f16_shortest_sanity_test < F > ( mut f : F )
244
+ where
245
+ F : for < ' a > FnMut ( & Decoded , & ' a mut [ MaybeUninit < u8 > ] ) -> ( & ' a [ u8 ] , i16 ) ,
246
+ {
247
+ // 0.0999145507813
248
+ // 0.0999755859375
249
+ // 0.100036621094
250
+ check_shortest ! ( f( 0.1f16 ) => b"1" , 0 ) ;
251
+
252
+ // 0.3330078125
253
+ // 0.333251953125 (1/3 in the default rounding)
254
+ // 0.33349609375
255
+ check_shortest ! ( f( 1.0f16 /3.0 ) => b"3333" , 0 ) ;
256
+
257
+ // 10^1 * 0.3138671875
258
+ // 10^1 * 0.3140625
259
+ // 10^1 * 0.3142578125
260
+ check_shortest ! ( f( 3.14f16 ) => b"314" , 1 ) ;
261
+
262
+ // 10^18 * 0.31415916243714048
263
+ // 10^18 * 0.314159196796878848
264
+ // 10^18 * 0.314159231156617216
265
+ check_shortest ! ( f( 3.1415e4f16 ) => b"3141" , 5 ) ;
266
+
267
+ // regression test for decoders
268
+ // 10^2 * 0.31984375
269
+ // 10^2 * 0.32
270
+ // 10^2 * 0.3203125
271
+ check_shortest ! ( f( ldexp_f16( 1.0 , 5 ) ) => b"32" , 2 ) ;
272
+
273
+ // 10^5 * 0.65472
274
+ // 10^5 * 0.65504
275
+ // 10^5 * 0.65536
276
+ check_shortest ! ( f( f16:: MAX ) => b"655" , 5 ) ;
277
+
278
+ // 10^-4 * 0.60975551605224609375
279
+ // 10^-4 * 0.6103515625
280
+ // 10^-4 * 0.61094760894775390625
281
+ check_shortest ! ( f( f16:: MIN_POSITIVE ) => b"6104" , -4 ) ;
282
+
283
+ // 10^-9 * 0
284
+ // 10^-9 * 0.59604644775390625
285
+ // 10^-8 * 0.11920928955078125
286
+ let minf16 = ldexp_f16 ( 1.0 , -24 ) ;
287
+ check_shortest ! ( f( minf16) => b"6" , -7 ) ;
288
+ }
289
+
290
+ #[ cfg( target_has_reliable_f16) ]
291
+ pub fn f16_exact_sanity_test < F > ( mut f : F )
292
+ where
293
+ F : for < ' a > FnMut ( & Decoded , & ' a mut [ MaybeUninit < u8 > ] , i16 ) -> ( & ' a [ u8 ] , i16 ) ,
294
+ {
295
+ let minf16 = ldexp_f16 ( 1.0 , -24 ) ;
296
+
297
+ check_exact ! ( f( 0.1f16 ) => b"999755859375 " , -1 ) ;
298
+ check_exact ! ( f( 0.5f16 ) => b"5 " , 0 ) ;
299
+ check_exact ! ( f( 1.0f16 /3.0 ) => b"333251953125 " , 0 ) ;
300
+ check_exact ! ( f( 3.141f16 ) => b"3140625 " , 1 ) ;
301
+ check_exact ! ( f( 3.141e4f16 ) => b"31408 " , 5 ) ;
302
+ check_exact ! ( f( f16:: MAX ) => b"65504 " , 5 ) ;
303
+ check_exact ! ( f( f16:: MIN_POSITIVE ) => b"6103515625 " , -4 ) ;
304
+ check_exact ! ( f( minf16) => b"59604644775390625" , -7 ) ;
305
+
306
+ // FIXME(f16_f128): these should gain the check_exact_one tests like `f32` and `f64` have,
307
+ // but these values are not easy to generate. The algorithm from the Paxon paper [1] needs
308
+ // to be adapted to binary16.
309
+ }
228
310
229
311
pub fn f32_shortest_sanity_test < F > ( mut f : F )
230
312
where
@@ -553,23 +635,45 @@ where
553
635
assert_eq ! ( to_string( f, 1.9971e20 , Minus , 1 ) , "199710000000000000000.0" ) ;
554
636
assert_eq ! ( to_string( f, 1.9971e20 , Minus , 8 ) , "199710000000000000000.00000000" ) ;
555
637
556
- assert_eq ! ( to_string( f, f32 :: MAX , Minus , 0 ) , format!( "34028235{:0>31}" , "" ) ) ;
557
- assert_eq ! ( to_string( f, f32 :: MAX , Minus , 1 ) , format!( "34028235{:0>31}.0" , "" ) ) ;
558
- assert_eq ! ( to_string( f, f32 :: MAX , Minus , 8 ) , format!( "34028235{:0>31}.00000000" , "" ) ) ;
559
-
560
- let minf32 = ldexp_f32 ( 1.0 , -149 ) ;
561
- assert_eq ! ( to_string( f, minf32, Minus , 0 ) , format!( "0.{:0>44}1" , "" ) ) ;
562
- assert_eq ! ( to_string( f, minf32, Minus , 45 ) , format!( "0.{:0>44}1" , "" ) ) ;
563
- assert_eq ! ( to_string( f, minf32, Minus , 46 ) , format!( "0.{:0>44}10" , "" ) ) ;
638
+ #[ cfg( target_has_reliable_f16) ]
639
+ {
640
+ // f16
641
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 0 ) , "65500" ) ;
642
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 1 ) , "65500.0" ) ;
643
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 8 ) , "65500.00000000" ) ;
644
+
645
+ let minf16 = ldexp_f16 ( 1.0 , -24 ) ;
646
+ assert_eq ! ( to_string( f, minf16, Minus , 0 ) , "0.00000006" ) ;
647
+ assert_eq ! ( to_string( f, minf16, Minus , 8 ) , "0.00000006" ) ;
648
+ assert_eq ! ( to_string( f, minf16, Minus , 9 ) , "0.000000060" ) ;
649
+ }
564
650
565
- assert_eq ! ( to_string( f, f64 :: MAX , Minus , 0 ) , format!( "17976931348623157{:0>292}" , "" ) ) ;
566
- assert_eq ! ( to_string( f, f64 :: MAX , Minus , 1 ) , format!( "17976931348623157{:0>292}.0" , "" ) ) ;
567
- assert_eq ! ( to_string( f, f64 :: MAX , Minus , 8 ) , format!( "17976931348623157{:0>292}.00000000" , "" ) ) ;
651
+ {
652
+ // f32
653
+ assert_eq ! ( to_string( f, f32 :: MAX , Minus , 0 ) , format!( "34028235{:0>31}" , "" ) ) ;
654
+ assert_eq ! ( to_string( f, f32 :: MAX , Minus , 1 ) , format!( "34028235{:0>31}.0" , "" ) ) ;
655
+ assert_eq ! ( to_string( f, f32 :: MAX , Minus , 8 ) , format!( "34028235{:0>31}.00000000" , "" ) ) ;
656
+
657
+ let minf32 = ldexp_f32 ( 1.0 , -149 ) ;
658
+ assert_eq ! ( to_string( f, minf32, Minus , 0 ) , format!( "0.{:0>44}1" , "" ) ) ;
659
+ assert_eq ! ( to_string( f, minf32, Minus , 45 ) , format!( "0.{:0>44}1" , "" ) ) ;
660
+ assert_eq ! ( to_string( f, minf32, Minus , 46 ) , format!( "0.{:0>44}10" , "" ) ) ;
661
+ }
568
662
569
- let minf64 = ldexp_f64 ( 1.0 , -1074 ) ;
570
- assert_eq ! ( to_string( f, minf64, Minus , 0 ) , format!( "0.{:0>323}5" , "" ) ) ;
571
- assert_eq ! ( to_string( f, minf64, Minus , 324 ) , format!( "0.{:0>323}5" , "" ) ) ;
572
- assert_eq ! ( to_string( f, minf64, Minus , 325 ) , format!( "0.{:0>323}50" , "" ) ) ;
663
+ {
664
+ // f64
665
+ assert_eq ! ( to_string( f, f64 :: MAX , Minus , 0 ) , format!( "17976931348623157{:0>292}" , "" ) ) ;
666
+ assert_eq ! ( to_string( f, f64 :: MAX , Minus , 1 ) , format!( "17976931348623157{:0>292}.0" , "" ) ) ;
667
+ assert_eq ! (
668
+ to_string( f, f64 :: MAX , Minus , 8 ) ,
669
+ format!( "17976931348623157{:0>292}.00000000" , "" )
670
+ ) ;
671
+
672
+ let minf64 = ldexp_f64 ( 1.0 , -1074 ) ;
673
+ assert_eq ! ( to_string( f, minf64, Minus , 0 ) , format!( "0.{:0>323}5" , "" ) ) ;
674
+ assert_eq ! ( to_string( f, minf64, Minus , 324 ) , format!( "0.{:0>323}5" , "" ) ) ;
675
+ assert_eq ! ( to_string( f, minf64, Minus , 325 ) , format!( "0.{:0>323}50" , "" ) ) ;
676
+ }
573
677
574
678
if cfg ! ( miri) {
575
679
// Miri is too slow
@@ -655,27 +759,45 @@ where
655
759
assert_eq ! ( to_string( f, 1.0e23 , Minus , ( 23 , 24 ) , false ) , "100000000000000000000000" ) ;
656
760
assert_eq ! ( to_string( f, 1.0e23 , Minus , ( 24 , 25 ) , false ) , "1e23" ) ;
657
761
658
- assert_eq ! ( to_string( f, f32 :: MAX , Minus , ( -4 , 16 ) , false ) , "3.4028235e38" ) ;
659
- assert_eq ! ( to_string( f, f32 :: MAX , Minus , ( -39 , 38 ) , false ) , "3.4028235e38" ) ;
660
- assert_eq ! ( to_string( f, f32 :: MAX , Minus , ( -38 , 39 ) , false ) , format!( "34028235{:0>31}" , "" ) ) ;
661
-
662
- let minf32 = ldexp_f32 ( 1.0 , -149 ) ;
663
- assert_eq ! ( to_string( f, minf32, Minus , ( -4 , 16 ) , false ) , "1e-45" ) ;
664
- assert_eq ! ( to_string( f, minf32, Minus , ( -44 , 45 ) , false ) , "1e-45" ) ;
665
- assert_eq ! ( to_string( f, minf32, Minus , ( -45 , 44 ) , false ) , format!( "0.{:0>44}1" , "" ) ) ;
666
-
667
- assert_eq ! ( to_string( f, f64 :: MAX , Minus , ( -4 , 16 ) , false ) , "1.7976931348623157e308" ) ;
668
- assert_eq ! (
669
- to_string( f, f64 :: MAX , Minus , ( -308 , 309 ) , false ) ,
670
- format!( "17976931348623157{:0>292}" , "" )
671
- ) ;
672
- assert_eq ! ( to_string( f, f64 :: MAX , Minus , ( -309 , 308 ) , false ) , "1.7976931348623157e308" ) ;
762
+ #[ cfg( target_has_reliable_f16) ]
763
+ {
764
+ // f16
765
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , ( -2 , 2 ) , false ) , "6.55e4" ) ;
766
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , ( -4 , 4 ) , false ) , "6.55e4" ) ;
767
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , ( -5 , 5 ) , false ) , "65500" ) ;
768
+
769
+ let minf16 = ldexp_f16 ( 1.0 , -24 ) ;
770
+ assert_eq ! ( to_string( f, minf16, Minus , ( -2 , 2 ) , false ) , "6e-8" ) ;
771
+ assert_eq ! ( to_string( f, minf16, Minus , ( -7 , 7 ) , false ) , "6e-8" ) ;
772
+ assert_eq ! ( to_string( f, minf16, Minus , ( -8 , 8 ) , false ) , "0.00000006" ) ;
773
+ }
673
774
674
- let minf64 = ldexp_f64 ( 1.0 , -1074 ) ;
675
- assert_eq ! ( to_string( f, minf64, Minus , ( -4 , 16 ) , false ) , "5e-324" ) ;
676
- assert_eq ! ( to_string( f, minf64, Minus , ( -324 , 323 ) , false ) , format!( "0.{:0>323}5" , "" ) ) ;
677
- assert_eq ! ( to_string( f, minf64, Minus , ( -323 , 324 ) , false ) , "5e-324" ) ;
775
+ {
776
+ // f32
777
+ assert_eq ! ( to_string( f, f32 :: MAX , Minus , ( -4 , 16 ) , false ) , "3.4028235e38" ) ;
778
+ assert_eq ! ( to_string( f, f32 :: MAX , Minus , ( -39 , 38 ) , false ) , "3.4028235e38" ) ;
779
+ assert_eq ! ( to_string( f, f32 :: MAX , Minus , ( -38 , 39 ) , false ) , format!( "34028235{:0>31}" , "" ) ) ;
780
+
781
+ let minf32 = ldexp_f32 ( 1.0 , -149 ) ;
782
+ assert_eq ! ( to_string( f, minf32, Minus , ( -4 , 16 ) , false ) , "1e-45" ) ;
783
+ assert_eq ! ( to_string( f, minf32, Minus , ( -44 , 45 ) , false ) , "1e-45" ) ;
784
+ assert_eq ! ( to_string( f, minf32, Minus , ( -45 , 44 ) , false ) , format!( "0.{:0>44}1" , "" ) ) ;
785
+ }
678
786
787
+ {
788
+ // f64
789
+ assert_eq ! ( to_string( f, f64 :: MAX , Minus , ( -4 , 16 ) , false ) , "1.7976931348623157e308" ) ;
790
+ assert_eq ! (
791
+ to_string( f, f64 :: MAX , Minus , ( -308 , 309 ) , false ) ,
792
+ format!( "17976931348623157{:0>292}" , "" )
793
+ ) ;
794
+ assert_eq ! ( to_string( f, f64 :: MAX , Minus , ( -309 , 308 ) , false ) , "1.7976931348623157e308" ) ;
795
+
796
+ let minf64 = ldexp_f64 ( 1.0 , -1074 ) ;
797
+ assert_eq ! ( to_string( f, minf64, Minus , ( -4 , 16 ) , false ) , "5e-324" ) ;
798
+ assert_eq ! ( to_string( f, minf64, Minus , ( -324 , 323 ) , false ) , format!( "0.{:0>323}5" , "" ) ) ;
799
+ assert_eq ! ( to_string( f, minf64, Minus , ( -323 , 324 ) , false ) , "5e-324" ) ;
800
+ }
679
801
assert_eq ! ( to_string( f, 1.1 , Minus , ( i16 :: MIN , i16 :: MAX ) , false ) , "1.1" ) ;
680
802
}
681
803
@@ -791,6 +913,26 @@ where
791
913
"9.999999999999999547481118258862586856139387236908078193664550781250000e-7"
792
914
) ;
793
915
916
+ #[ cfg( target_has_reliable_f16) ]
917
+ {
918
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 1 , false ) , "7e4" ) ;
919
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 2 , false ) , "6.6e4" ) ;
920
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 4 , false ) , "6.550e4" ) ;
921
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 5 , false ) , "6.5504e4" ) ;
922
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 6 , false ) , "6.55040e4" ) ;
923
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 16 , false ) , "6.550400000000000e4" ) ;
924
+
925
+ let minf16 = ldexp_f16 ( 1.0 , -24 ) ;
926
+ assert_eq ! ( to_string( f, minf16, Minus , 1 , false ) , "6e-8" ) ;
927
+ assert_eq ! ( to_string( f, minf16, Minus , 2 , false ) , "6.0e-8" ) ;
928
+ assert_eq ! ( to_string( f, minf16, Minus , 4 , false ) , "5.960e-8" ) ;
929
+ assert_eq ! ( to_string( f, minf16, Minus , 8 , false ) , "5.9604645e-8" ) ;
930
+ assert_eq ! ( to_string( f, minf16, Minus , 16 , false ) , "5.960464477539062e-8" ) ;
931
+ assert_eq ! ( to_string( f, minf16, Minus , 17 , false ) , "5.9604644775390625e-8" ) ;
932
+ assert_eq ! ( to_string( f, minf16, Minus , 18 , false ) , "5.96046447753906250e-8" ) ;
933
+ assert_eq ! ( to_string( f, minf16, Minus , 24 , false ) , "5.96046447753906250000000e-8" ) ;
934
+ }
935
+
794
936
assert_eq ! ( to_string( f, f32 :: MAX , Minus , 1 , false ) , "3e38" ) ;
795
937
assert_eq ! ( to_string( f, f32 :: MAX , Minus , 2 , false ) , "3.4e38" ) ;
796
938
assert_eq ! ( to_string( f, f32 :: MAX , Minus , 4 , false ) , "3.403e38" ) ;
@@ -1069,6 +1211,13 @@ where
1069
1211
"0.000000999999999999999954748111825886258685613938723690807819366455078125000"
1070
1212
) ;
1071
1213
1214
+ #[ cfg( target_has_reliable_f16) ]
1215
+ {
1216
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 0 ) , "65504" ) ;
1217
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 1 ) , "65504.0" ) ;
1218
+ assert_eq ! ( to_string( f, f16:: MAX , Minus , 2 ) , "65504.00" ) ;
1219
+ }
1220
+
1072
1221
assert_eq ! ( to_string( f, f32 :: MAX , Minus , 0 ) , "340282346638528859811704183484516925440" ) ;
1073
1222
assert_eq ! ( to_string( f, f32 :: MAX , Minus , 1 ) , "340282346638528859811704183484516925440.0" ) ;
1074
1223
assert_eq ! ( to_string( f, f32 :: MAX , Minus , 2 ) , "340282346638528859811704183484516925440.00" ) ;
@@ -1078,6 +1227,21 @@ where
1078
1227
return ;
1079
1228
}
1080
1229
1230
+ #[ cfg( target_has_reliable_f16) ]
1231
+ {
1232
+ let minf16 = ldexp_f16 ( 1.0 , -24 ) ;
1233
+ assert_eq ! ( to_string( f, minf16, Minus , 0 ) , "0" ) ;
1234
+ assert_eq ! ( to_string( f, minf16, Minus , 1 ) , "0.0" ) ;
1235
+ assert_eq ! ( to_string( f, minf16, Minus , 2 ) , "0.00" ) ;
1236
+ assert_eq ! ( to_string( f, minf16, Minus , 4 ) , "0.0000" ) ;
1237
+ assert_eq ! ( to_string( f, minf16, Minus , 8 ) , "0.00000006" ) ;
1238
+ assert_eq ! ( to_string( f, minf16, Minus , 10 ) , "0.0000000596" ) ;
1239
+ assert_eq ! ( to_string( f, minf16, Minus , 15 ) , "0.000000059604645" ) ;
1240
+ assert_eq ! ( to_string( f, minf16, Minus , 20 ) , "0.00000005960464477539" ) ;
1241
+ assert_eq ! ( to_string( f, minf16, Minus , 24 ) , "0.000000059604644775390625" ) ;
1242
+ assert_eq ! ( to_string( f, minf16, Minus , 32 ) , "0.00000005960464477539062500000000" ) ;
1243
+ }
1244
+
1081
1245
let minf32 = ldexp_f32 ( 1.0 , -149 ) ;
1082
1246
assert_eq ! ( to_string( f, minf32, Minus , 0 ) , "0" ) ;
1083
1247
assert_eq ! ( to_string( f, minf32, Minus , 1 ) , "0.0" ) ;
0 commit comments