44
55use super :: { f32_from_bits, f64_from_bits} ;
66
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+
713/// Construct a 32-bit float from hex float representation (C-style)
814pub const fn hf32 ( s : & str ) -> f32 {
915 f32_from_bits ( parse_any ( s, 32 , 23 ) as u32 )
@@ -14,6 +20,12 @@ pub const fn hf64(s: &str) -> f64 {
1420 f64_from_bits ( parse_any ( s, 64 , 52 ) as u64 )
1521}
1622
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+
1729const fn parse_any ( s : & str , bits : u32 , sig_bits : u32 ) -> u128 {
1830 let exp_bits: u32 = bits - sig_bits - 1 ;
1931 let max_msb: i32 = ( 1 << ( exp_bits - 1 ) ) - 1 ;
@@ -230,6 +242,57 @@ mod tests {
230242 }
231243 }
232244
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+
233296 #[ test]
234297 fn test_f32 ( ) {
235298 let checks = [
@@ -308,16 +371,67 @@ mod tests {
308371 }
309372 }
310373
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+ }
315420 }
316421
422+ #[ cfg( f128_enabled) ]
423+ f128_tests ! ( ) ;
424+
317425 #[ test]
318426 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);
321435 }
322436}
323437
@@ -328,6 +442,69 @@ mod tests_panicking {
328442 extern crate std;
329443 use super :: * ;
330444
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+
331508 #[ test]
332509 #[ should_panic]
333510 fn test_f32_extra_precision2 ( ) {
@@ -388,4 +565,61 @@ mod tests_panicking {
388565 // One bit more than the above.
389566 hf64 ( "0x1.abcdabcdabcdf8p+0" ) ;
390567 }
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 ! ( ) ;
391625}
0 commit comments