@@ -26,17 +26,25 @@ pub const fn hf128(s: &str) -> f128 {
2626 f128:: from_bits ( parse_any ( s, 128 , 112 ) )
2727}
2828
29- const fn parse_any ( s : & str , bits : u32 , sig_bits : u32 ) -> u128 {
29+ /// Parse any float from hex to its bitwise representation.
30+ ///
31+ /// `nan_repr` is passed rather than constructed so the platform-specific NaN is returned.
32+ pub const fn parse_any ( s : & str , bits : u32 , sig_bits : u32 ) -> u128 {
3033 let exp_bits: u32 = bits - sig_bits - 1 ;
3134 let max_msb: i32 = ( 1 << ( exp_bits - 1 ) ) - 1 ;
3235 // The exponent of one ULP in the subnormals
3336 let min_lsb: i32 = 1 - max_msb - sig_bits as i32 ;
3437
35- let ( neg , mut sig , exp ) = parse_hex ( s . as_bytes ( ) ) ;
38+ let exp_mask = ( ( 1 << exp_bits ) - 1 ) << sig_bits ;
3639
37- if sig == 0 {
38- return ( neg as u128 ) << ( bits - 1 ) ;
39- }
40+ let ( neg, mut sig, exp) = match parse_hex ( s. as_bytes ( ) ) {
41+ Parsed :: Finite { neg, sig : 0 , .. } => return ( neg as u128 ) << ( bits - 1 ) ,
42+ Parsed :: Finite { neg, sig, exp } => ( neg, sig, exp) ,
43+ Parsed :: Infinite { neg } => return ( ( neg as u128 ) << ( bits - 1 ) ) | exp_mask,
44+ Parsed :: Nan { neg } => {
45+ return ( ( neg as u128 ) << ( bits - 1 ) ) | exp_mask | 1 << ( sig_bits - 1 ) ;
46+ }
47+ } ;
4048
4149 // exponents of the least and most significant bits in the value
4250 let lsb = sig. trailing_zeros ( ) as i32 ;
@@ -76,11 +84,24 @@ const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 {
7684 sig | ( ( neg as u128 ) << ( bits - 1 ) )
7785}
7886
87+ /// A parsed floating point number.
88+ enum Parsed {
89+ /// Absolute value sig * 2^e
90+ Finite {
91+ neg : bool ,
92+ sig : u128 ,
93+ exp : i32 ,
94+ } ,
95+ Infinite {
96+ neg : bool ,
97+ } ,
98+ Nan {
99+ neg : bool ,
100+ } ,
101+ }
102+
79103/// Parse a hexadecimal float x
80- /// returns (s,n,e):
81- /// s == x.is_sign_negative()
82- /// n * 2^e == x.abs()
83- const fn parse_hex ( mut b : & [ u8 ] ) -> ( bool , u128 , i32 ) {
104+ const fn parse_hex ( mut b : & [ u8 ] ) -> Parsed {
84105 let mut neg = false ;
85106 let mut sig: u128 = 0 ;
86107 let mut exp: i32 = 0 ;
@@ -90,6 +111,12 @@ const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) {
90111 neg = c == b'-' ;
91112 }
92113
114+ match * b {
115+ [ b'i' | b'I' , b'n' | b'N' , b'f' | b'F' ] => return Parsed :: Infinite { neg } ,
116+ [ b'n' | b'N' , b'a' | b'A' , b'n' | b'N' ] => return Parsed :: Nan { neg } ,
117+ _ => ( ) ,
118+ }
119+
93120 if let & [ b'0' , b'x' | b'X' , ref rest @ ..] = b {
94121 b = rest;
95122 } else {
@@ -152,7 +179,7 @@ const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) {
152179 exp += pexp;
153180 }
154181
155- ( neg, sig, exp)
182+ Parsed :: Finite { neg, sig, exp }
156183}
157184
158185const fn dec_digit ( c : u8 ) -> u8 {
@@ -272,6 +299,10 @@ mod tests {
272299 ( "-0x1.998p-4" , ( -0.1f16 ) . to_bits( ) ) ,
273300 ( "0x0.123p-12" , 0x0123 ) ,
274301 ( "0x1p-24" , 0x0001 ) ,
302+ ( "nan" , f16:: NAN . to_bits( ) ) ,
303+ ( "-nan" , ( -f16:: NAN ) . to_bits( ) ) ,
304+ ( "inf" , f16:: INFINITY . to_bits( ) ) ,
305+ ( "-inf" , f16:: NEG_INFINITY . to_bits( ) ) ,
275306 ] ;
276307 for ( s, exp) in checks {
277308 println!( "parsing {s}" ) ;
@@ -322,6 +353,10 @@ mod tests {
322353 ( "0x1.111114p-127" , 0x00444445 ) ,
323354 ( "0x1.23456p-130" , 0x00091a2b ) ,
324355 ( "0x1p-149" , 0x00000001 ) ,
356+ ( "nan" , f32:: NAN . to_bits ( ) ) ,
357+ ( "-nan" , ( -f32:: NAN ) . to_bits ( ) ) ,
358+ ( "inf" , f32:: INFINITY . to_bits ( ) ) ,
359+ ( "-inf" , f32:: NEG_INFINITY . to_bits ( ) ) ,
325360 ] ;
326361 for ( s, exp) in checks {
327362 println ! ( "parsing {s}" ) ;
@@ -360,6 +395,10 @@ mod tests {
360395 ( "0x0.8000000000001p-1022" , 0x0008000000000001 ) ,
361396 ( "0x0.123456789abcdp-1022" , 0x000123456789abcd ) ,
362397 ( "0x0.0000000000002p-1022" , 0x0000000000000002 ) ,
398+ ( "nan" , f64:: NAN . to_bits ( ) ) ,
399+ ( "-nan" , ( -f64:: NAN ) . to_bits ( ) ) ,
400+ ( "inf" , f64:: INFINITY . to_bits ( ) ) ,
401+ ( "-inf" , f64:: NEG_INFINITY . to_bits ( ) ) ,
363402 ] ;
364403 for ( s, exp) in checks {
365404 println ! ( "parsing {s}" ) ;
@@ -401,6 +440,10 @@ mod tests {
401440 ( "-0x1.999999999999999999999999999ap-4" , ( -0.1f128 ) . to_bits( ) ) ,
402441 ( "0x0.abcdef0123456789abcdef012345p-16382" , 0x0000abcdef0123456789abcdef012345 ) ,
403442 ( "0x1p-16494" , 0x00000000000000000000000000000001 ) ,
443+ ( "nan" , f128:: NAN . to_bits( ) ) ,
444+ ( "-nan" , ( -f128:: NAN ) . to_bits( ) ) ,
445+ ( "inf" , f128:: INFINITY . to_bits( ) ) ,
446+ ( "-inf" , f128:: NEG_INFINITY . to_bits( ) ) ,
404447 ] ;
405448 for ( s, exp) in checks {
406449 println!( "parsing {s}" ) ;
0 commit comments