Skip to content

Commit 4a6ba24

Browse files
committed
float: Add f16 parsing and printing
Use the existing Lemire (decimal -> float) and Dragon / Grisu algorithms (float -> decimal) to add support for `f16`. This allows updating the implementation for `Display` to the expected behavior for `Display` (currently it prints the a hex bitwise representation) and adds a `FromStr` implementation.
1 parent 1b8ab72 commit 4a6ba24

File tree

4 files changed

+62
-13
lines changed

4 files changed

+62
-13
lines changed

library/core/src/fmt/float.rs

+2-9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ macro_rules! impl_general_format {
2020
}
2121
}
2222

23+
impl_general_format! { f16 }
2324
impl_general_format! { f32 f64 }
2425

2526
// Don't inline this so callers don't use the stack space this function
@@ -229,15 +230,7 @@ macro_rules! floating {
229230
};
230231
}
231232

232-
floating! { f32 f64 }
233-
234-
#[stable(feature = "rust1", since = "1.0.0")]
235-
impl Debug for f16 {
236-
#[inline]
237-
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
238-
write!(f, "{:#06x}", self.to_bits())
239-
}
240-
}
233+
floating! { f16 f32 f64 }
241234

242235
#[stable(feature = "rust1", since = "1.0.0")]
243236
impl Debug for f128 {

library/core/src/num/dec2flt/float.rs

+52-4
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ macro_rules! int {
4545
}
4646
}
4747

48-
int!(u32, u64);
48+
int!(u16, u32, u64);
4949

5050
/// A helper trait to avoid duplicating basically all the conversion code for IEEE floats.
5151
///
@@ -189,9 +189,14 @@ pub trait RawFloat:
189189

190190
/// Returns the mantissa, exponent and sign as integers.
191191
///
192-
/// That is, this returns `(m, p, s)` such that `s * m * 2^p` represents the original float.
193-
/// For 0, the exponent will be `-(EXP_BIAS + SIG_BITS`, which is the
194-
/// minimum subnormal power.
192+
/// This returns `(m, p, s)` such that `s * m * 2^p` represents the original float. For 0, the
193+
/// exponent will be `-(EXP_BIAS + SIG_BITS)`, which is the minimum subnormal power. For
194+
/// infinity or NaN, the exponent will be `EXP_SAT - EXP_BIAS - SIG_BITS`.
195+
///
196+
/// If subnormal, the mantissa will be shifted one bit to the left. Otherwise, it is returned
197+
/// with the explicit bit set but otherwise unshifted
198+
///
199+
/// `s` is only ever +/-1.
195200
fn integer_decode(self) -> (u64, i16, i8) {
196201
let bits = self.to_bits();
197202
let sign: i8 = if bits >> (Self::BITS - 1) == Self::Int::ZERO { 1 } else { -1 };
@@ -213,6 +218,49 @@ const fn pow2_to_pow10(a: i64) -> i64 {
213218
res as i64
214219
}
215220

221+
impl RawFloat for f16 {
222+
type Int = u16;
223+
224+
const INFINITY: Self = Self::INFINITY;
225+
const NEG_INFINITY: Self = Self::NEG_INFINITY;
226+
const NAN: Self = Self::NAN;
227+
const NEG_NAN: Self = -Self::NAN;
228+
229+
const BITS: u32 = 16;
230+
const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS;
231+
const EXP_MASK: Self::Int = Self::EXP_MASK;
232+
const SIG_MASK: Self::Int = Self::MAN_MASK;
233+
234+
const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -22;
235+
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 5;
236+
const SMALLEST_POWER_OF_TEN: i32 = -27;
237+
238+
#[inline]
239+
fn from_u64(v: u64) -> Self {
240+
debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
241+
v as _
242+
}
243+
244+
#[inline]
245+
fn from_u64_bits(v: u64) -> Self {
246+
Self::from_bits((v & 0xFFFF) as u16)
247+
}
248+
249+
fn pow10_fast_path(exponent: usize) -> Self {
250+
#[allow(clippy::use_self)]
251+
const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.];
252+
TABLE[exponent & 7]
253+
}
254+
255+
fn to_bits(self) -> Self::Int {
256+
self.to_bits()
257+
}
258+
259+
fn classify(self) -> FpCategory {
260+
self.classify()
261+
}
262+
}
263+
216264
impl RawFloat for f32 {
217265
type Int = u32;
218266

library/core/src/num/dec2flt/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ macro_rules! from_str_float_impl {
171171
}
172172
};
173173
}
174+
175+
from_str_float_impl!(f16);
174176
from_str_float_impl!(f32);
175177
from_str_float_impl!(f64);
176178

library/core/src/num/flt2dec/decoder.rs

+6
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ pub trait DecodableFloat: RawFloat + Copy {
4545
fn min_pos_norm_value() -> Self;
4646
}
4747

48+
impl DecodableFloat for f16 {
49+
fn min_pos_norm_value() -> Self {
50+
f16::MIN_POSITIVE
51+
}
52+
}
53+
4854
impl DecodableFloat for f32 {
4955
fn min_pos_norm_value() -> Self {
5056
f32::MIN_POSITIVE

0 commit comments

Comments
 (0)