4
4
5
5
use super :: { f32_from_bits, f64_from_bits} ;
6
6
7
+ /// Construct a 16-bit float from hex float representation (C-style)
8
+ #[ cfg( f16_enabled) ]
9
+ pub const fn hf16 ( s : & str ) -> f16 {
10
+ f16:: from_bits ( parse_any ( s, 16 , 10 ) as u16 )
11
+ }
12
+
7
13
/// Construct a 32-bit float from hex float representation (C-style)
8
14
pub const fn hf32 ( s : & str ) -> f32 {
9
15
f32_from_bits ( parse_any ( s, 32 , 23 ) as u32 )
@@ -14,6 +20,12 @@ pub const fn hf64(s: &str) -> f64 {
14
20
f64_from_bits ( parse_any ( s, 64 , 52 ) as u64 )
15
21
}
16
22
23
+ /// Construct a 128-bit float from hex float representation (C-style)
24
+ #[ cfg( f128_enabled) ]
25
+ pub const fn hf128 ( s : & str ) -> f128 {
26
+ f128:: from_bits ( parse_any ( s, 128 , 112 ) )
27
+ }
28
+
17
29
const fn parse_any ( s : & str , bits : u32 , sig_bits : u32 ) -> u128 {
18
30
let exp_bits: u32 = bits - sig_bits - 1 ;
19
31
let max_msb: i32 = ( 1 << ( exp_bits - 1 ) ) - 1 ;
@@ -230,6 +242,57 @@ mod tests {
230
242
}
231
243
}
232
244
245
+ // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to
246
+ // hide them from the AST.
247
+ #[ cfg( f16_enabled) ]
248
+ macro_rules! f16_tests {
249
+ ( ) => {
250
+ #[ test]
251
+ fn test_f16( ) {
252
+ let checks = [
253
+ ( "0x.1234p+16" , ( 0x1234 as f16) . to_bits( ) ) ,
254
+ ( "0x1.234p+12" , ( 0x1234 as f16) . to_bits( ) ) ,
255
+ ( "0x12.34p+8" , ( 0x1234 as f16) . to_bits( ) ) ,
256
+ ( "0x123.4p+4" , ( 0x1234 as f16) . to_bits( ) ) ,
257
+ ( "0x1234p+0" , ( 0x1234 as f16) . to_bits( ) ) ,
258
+ ( "0x1234.p+0" , ( 0x1234 as f16) . to_bits( ) ) ,
259
+ ( "0x1234.0p+0" , ( 0x1234 as f16) . to_bits( ) ) ,
260
+ ( "0x1.ffcp+15" , f16:: MAX . to_bits( ) ) ,
261
+ ( "0x1.0p+1" , 2.0f16 . to_bits( ) ) ,
262
+ ( "0x1.0p+0" , 1.0f16 . to_bits( ) ) ,
263
+ ( "0x1.ffp+8" , 0x5ffc ) ,
264
+ ( "+0x1.ffp+8" , 0x5ffc ) ,
265
+ ( "0x1p+0" , 0x3c00 ) ,
266
+ ( "0x1.998p-4" , 0x2e66 ) ,
267
+ ( "0x1.9p+6" , 0x5640 ) ,
268
+ ( "0x0.0p0" , 0.0f16 . to_bits( ) ) ,
269
+ ( "-0x0.0p0" , ( -0.0f16 ) . to_bits( ) ) ,
270
+ ( "0x1.0p0" , 1.0f16 . to_bits( ) ) ,
271
+ ( "0x1.998p-4" , ( 0.1f16 ) . to_bits( ) ) ,
272
+ ( "-0x1.998p-4" , ( -0.1f16 ) . to_bits( ) ) ,
273
+ ( "0x0.123p-12" , 0x0123 ) ,
274
+ ( "0x1p-24" , 0x0001 ) ,
275
+ ] ;
276
+ for ( s, exp) in checks {
277
+ println!( "parsing {s}" ) ;
278
+ let act = hf16( s) . to_bits( ) ;
279
+ assert_eq!(
280
+ act, exp,
281
+ "parsing {s}: {act:#06x} != {exp:#06x}\n act: {act:#018b}\n exp: {exp:#018b}"
282
+ ) ;
283
+ }
284
+ }
285
+
286
+ #[ test]
287
+ fn test_macros_f16( ) {
288
+ assert_eq!( hf16!( "0x1.ffp+8" ) . to_bits( ) , 0x5ffc_u16 ) ;
289
+ }
290
+ } ;
291
+ }
292
+
293
+ #[ cfg( f16_enabled) ]
294
+ f16_tests ! ( ) ;
295
+
233
296
#[ test]
234
297
fn test_f32 ( ) {
235
298
let checks = [
@@ -308,16 +371,67 @@ mod tests {
308
371
}
309
372
}
310
373
311
- #[ test]
312
- fn test_f32_almost_extra_precision ( ) {
313
- // Exact maximum precision allowed
314
- hf32 ( "0x1.abcdeep+0" ) ;
374
+ // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to
375
+ // hide them from the AST.
376
+ #[ cfg( f128_enabled) ]
377
+ macro_rules! f128_tests {
378
+ ( ) => {
379
+ #[ test]
380
+ fn test_f128( ) {
381
+ let checks = [
382
+ ( "0x.1234p+16" , ( 0x1234 as f128) . to_bits( ) ) ,
383
+ ( "0x1.234p+12" , ( 0x1234 as f128) . to_bits( ) ) ,
384
+ ( "0x12.34p+8" , ( 0x1234 as f128) . to_bits( ) ) ,
385
+ ( "0x123.4p+4" , ( 0x1234 as f128) . to_bits( ) ) ,
386
+ ( "0x1234p+0" , ( 0x1234 as f128) . to_bits( ) ) ,
387
+ ( "0x1234.p+0" , ( 0x1234 as f128) . to_bits( ) ) ,
388
+ ( "0x1234.0p+0" , ( 0x1234 as f128) . to_bits( ) ) ,
389
+ ( "0x1.ffffffffffffffffffffffffffffp+16383" , f128:: MAX . to_bits( ) ) ,
390
+ ( "0x1.0p+1" , 2.0f128 . to_bits( ) ) ,
391
+ ( "0x1.0p+0" , 1.0f128 . to_bits( ) ) ,
392
+ ( "0x1.ffep+8" , 0x4007ffe0000000000000000000000000 ) ,
393
+ ( "+0x1.ffep+8" , 0x4007ffe0000000000000000000000000 ) ,
394
+ ( "0x1p+0" , 0x3fff0000000000000000000000000000 ) ,
395
+ ( "0x1.999999999999999999999999999ap-4" , 0x3ffb999999999999999999999999999a ) ,
396
+ ( "0x1.9p+6" , 0x40059000000000000000000000000000 ) ,
397
+ ( "0x0.0p0" , 0.0f128 . to_bits( ) ) ,
398
+ ( "-0x0.0p0" , ( -0.0f128 ) . to_bits( ) ) ,
399
+ ( "0x1.0p0" , 1.0f128 . to_bits( ) ) ,
400
+ ( "0x1.999999999999999999999999999ap-4" , ( 0.1f128 ) . to_bits( ) ) ,
401
+ ( "-0x1.999999999999999999999999999ap-4" , ( -0.1f128 ) . to_bits( ) ) ,
402
+ ( "0x0.abcdef0123456789abcdef012345p-16382" , 0x0000abcdef0123456789abcdef012345 ) ,
403
+ ( "0x1p-16494" , 0x00000000000000000000000000000001 ) ,
404
+ ] ;
405
+ for ( s, exp) in checks {
406
+ println!( "parsing {s}" ) ;
407
+ let act = hf128( s) . to_bits( ) ;
408
+ assert_eq!(
409
+ act, exp,
410
+ "parsing {s}: {act:#034x} != {exp:#034x}\n act: {act:#0130b}\n exp: {exp:#0130b}"
411
+ ) ;
412
+ }
413
+ }
414
+
415
+ #[ test]
416
+ fn test_macros_f128( ) {
417
+ assert_eq!( hf128!( "0x1.ffep+8" ) . to_bits( ) , 0x4007ffe0000000000000000000000000_u128 ) ;
418
+ }
419
+ }
315
420
}
316
421
422
+ #[ cfg( f128_enabled) ]
423
+ f128_tests ! ( ) ;
424
+
317
425
#[ test]
318
426
fn test_macros ( ) {
319
- assert_eq ! ( hf32!( "0x1.ffep+8" ) . to_bits( ) , 0x43fff000u32 ) ;
320
- assert_eq ! ( hf64!( "0x1.ffep+8" ) . to_bits( ) , 0x407ffe0000000000u64 ) ;
427
+ // FIXME(msrv): enable once parsing works
428
+ // #[cfg(f16_enabled)]
429
+ // assert_eq!(hf16!("0x1.ffp+8").to_bits(), 0x5ffc_u16);
430
+ assert_eq ! ( hf32!( "0x1.ffep+8" ) . to_bits( ) , 0x43fff000_u32 ) ;
431
+ assert_eq ! ( hf64!( "0x1.ffep+8" ) . to_bits( ) , 0x407ffe0000000000_u64 ) ;
432
+ // FIXME(msrv): enable once parsing works
433
+ // #[cfg(f128_enabled)]
434
+ // assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128);
321
435
}
322
436
}
323
437
@@ -328,6 +442,69 @@ mod tests_panicking {
328
442
extern crate std;
329
443
use super :: * ;
330
444
445
+ // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to
446
+ // hide them from the AST.
447
+ #[ cfg( f16_enabled) ]
448
+ macro_rules! f16_tests {
449
+ ( ) => {
450
+ #[ test]
451
+ fn test_f16_almost_extra_precision( ) {
452
+ // Exact maximum precision allowed
453
+ hf16( "0x1.ffcp+0" ) ;
454
+ }
455
+
456
+ #[ test]
457
+ #[ should_panic( expected = "the value is too precise" ) ]
458
+ fn test_f16_extra_precision( ) {
459
+ // One bit more than the above.
460
+ hf16( "0x1.ffdp+0" ) ;
461
+ }
462
+
463
+ #[ test]
464
+ #[ should_panic( expected = "the value is too huge" ) ]
465
+ fn test_f16_overflow( ) {
466
+ // One bit more than the above.
467
+ hf16( "0x1p+16" ) ;
468
+ }
469
+
470
+ #[ test]
471
+ fn test_f16_tiniest( ) {
472
+ let x = hf16( "0x1.p-24" ) ;
473
+ let y = hf16( "0x0.001p-12" ) ;
474
+ let z = hf16( "0x0.8p-23" ) ;
475
+ assert_eq!( x, y) ;
476
+ assert_eq!( x, z) ;
477
+ }
478
+
479
+ #[ test]
480
+ #[ should_panic( expected = "the value is too tiny" ) ]
481
+ fn test_f16_too_tiny( ) {
482
+ hf16( "0x1.p-25" ) ;
483
+ }
484
+
485
+ #[ test]
486
+ #[ should_panic( expected = "the value is too tiny" ) ]
487
+ fn test_f16_also_too_tiny( ) {
488
+ hf16( "0x0.8p-24" ) ;
489
+ }
490
+
491
+ #[ test]
492
+ #[ should_panic( expected = "the value is too tiny" ) ]
493
+ fn test_f16_again_too_tiny( ) {
494
+ hf16( "0x0.001p-13" ) ;
495
+ }
496
+ } ;
497
+ }
498
+
499
+ #[ cfg( f16_enabled) ]
500
+ f16_tests ! ( ) ;
501
+
502
+ #[ test]
503
+ fn test_f32_almost_extra_precision ( ) {
504
+ // Exact maximum precision allowed
505
+ hf32 ( "0x1.abcdeep+0" ) ;
506
+ }
507
+
331
508
#[ test]
332
509
#[ should_panic]
333
510
fn test_f32_extra_precision2 ( ) {
@@ -388,4 +565,61 @@ mod tests_panicking {
388
565
// One bit more than the above.
389
566
hf64 ( "0x1.abcdabcdabcdf8p+0" ) ;
390
567
}
568
+
569
+ // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to
570
+ // hide them from the AST.
571
+ #[ cfg( f128_enabled) ]
572
+ macro_rules! f128_tests {
573
+ ( ) => {
574
+ #[ test]
575
+ fn test_f128_almost_extra_precision( ) {
576
+ // Exact maximum precision allowed
577
+ hf128( "0x1.ffffffffffffffffffffffffffffp+16383" ) ;
578
+ }
579
+
580
+ #[ test]
581
+ #[ should_panic( expected = "the value is too precise" ) ]
582
+ fn test_f128_extra_precision( ) {
583
+ // One bit more than the above.
584
+ hf128( "0x1.ffffffffffffffffffffffffffff8p+16383" ) ;
585
+ }
586
+
587
+ #[ test]
588
+ #[ should_panic( expected = "the value is too huge" ) ]
589
+ fn test_f128_overflow( ) {
590
+ // One bit more than the above.
591
+ hf128( "0x1p+16384" ) ;
592
+ }
593
+
594
+ #[ test]
595
+ fn test_f128_tiniest( ) {
596
+ let x = hf128( "0x1.p-16494" ) ;
597
+ let y = hf128( "0x0.0000000000000001p-16430" ) ;
598
+ let z = hf128( "0x0.8p-16493" ) ;
599
+ assert_eq!( x, y) ;
600
+ assert_eq!( x, z) ;
601
+ }
602
+
603
+ #[ test]
604
+ #[ should_panic( expected = "the value is too tiny" ) ]
605
+ fn test_f128_too_tiny( ) {
606
+ hf128( "0x1.p-16495" ) ;
607
+ }
608
+
609
+ #[ test]
610
+ #[ should_panic( expected = "the value is too tiny" ) ]
611
+ fn test_f128_again_too_tiny( ) {
612
+ hf128( "0x0.0000000000000001p-16431" ) ;
613
+ }
614
+
615
+ #[ test]
616
+ #[ should_panic( expected = "the value is too tiny" ) ]
617
+ fn test_f128_also_too_tiny( ) {
618
+ hf128( "0x0.8p-16494" ) ;
619
+ }
620
+ } ;
621
+ }
622
+
623
+ #[ cfg( f128_enabled) ]
624
+ f128_tests ! ( ) ;
391
625
}
0 commit comments