@@ -26,17 +26,25 @@ pub const fn hf128(s: &str) -> f128 {
26
26
f128:: from_bits ( parse_any ( s, 128 , 112 ) )
27
27
}
28
28
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 {
30
33
let exp_bits: u32 = bits - sig_bits - 1 ;
31
34
let max_msb: i32 = ( 1 << ( exp_bits - 1 ) ) - 1 ;
32
35
// The exponent of one ULP in the subnormals
33
36
let min_lsb: i32 = 1 - max_msb - sig_bits as i32 ;
34
37
35
- let ( neg , mut sig , exp ) = parse_hex ( s . as_bytes ( ) ) ;
38
+ let exp_mask = ( ( 1 << exp_bits ) - 1 ) << sig_bits ;
36
39
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
+ } ;
40
48
41
49
// exponents of the least and most significant bits in the value
42
50
let lsb = sig. trailing_zeros ( ) as i32 ;
@@ -76,11 +84,24 @@ const fn parse_any(s: &str, bits: u32, sig_bits: u32) -> u128 {
76
84
sig | ( ( neg as u128 ) << ( bits - 1 ) )
77
85
}
78
86
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
+
79
103
/// 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 {
84
105
let mut neg = false ;
85
106
let mut sig: u128 = 0 ;
86
107
let mut exp: i32 = 0 ;
@@ -90,6 +111,12 @@ const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) {
90
111
neg = c == b'-' ;
91
112
}
92
113
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
+
93
120
if let & [ b'0' , b'x' | b'X' , ref rest @ ..] = b {
94
121
b = rest;
95
122
} else {
@@ -152,7 +179,7 @@ const fn parse_hex(mut b: &[u8]) -> (bool, u128, i32) {
152
179
exp += pexp;
153
180
}
154
181
155
- ( neg, sig, exp)
182
+ Parsed :: Finite { neg, sig, exp }
156
183
}
157
184
158
185
const fn dec_digit ( c : u8 ) -> u8 {
@@ -272,6 +299,10 @@ mod tests {
272
299
( "-0x1.998p-4" , ( -0.1f16 ) . to_bits( ) ) ,
273
300
( "0x0.123p-12" , 0x0123 ) ,
274
301
( "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( ) ) ,
275
306
] ;
276
307
for ( s, exp) in checks {
277
308
println!( "parsing {s}" ) ;
@@ -322,6 +353,10 @@ mod tests {
322
353
( "0x1.111114p-127" , 0x00444445 ) ,
323
354
( "0x1.23456p-130" , 0x00091a2b ) ,
324
355
( "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 ( ) ) ,
325
360
] ;
326
361
for ( s, exp) in checks {
327
362
println ! ( "parsing {s}" ) ;
@@ -360,6 +395,10 @@ mod tests {
360
395
( "0x0.8000000000001p-1022" , 0x0008000000000001 ) ,
361
396
( "0x0.123456789abcdp-1022" , 0x000123456789abcd ) ,
362
397
( "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 ( ) ) ,
363
402
] ;
364
403
for ( s, exp) in checks {
365
404
println ! ( "parsing {s}" ) ;
@@ -401,6 +440,10 @@ mod tests {
401
440
( "-0x1.999999999999999999999999999ap-4" , ( -0.1f128 ) . to_bits( ) ) ,
402
441
( "0x0.abcdef0123456789abcdef012345p-16382" , 0x0000abcdef0123456789abcdef012345 ) ,
403
442
( "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( ) ) ,
404
447
] ;
405
448
for ( s, exp) in checks {
406
449
println!( "parsing {s}" ) ;
0 commit comments