lexical_parse_float/
float.rs

1//! Extended helper trait for generic float types.
2//!
3//! This adapted from the Rust implementation, based on the fast-float-rust
4//! implementation, and is similarly subject to an Apache2.0/MIT license.
5
6#![doc(hidden)]
7
8#[cfg(all(not(feature = "std"), feature = "compact"))]
9use crate::libm::{powd, powf};
10use crate::limits::{ExactFloat, MaxDigits};
11#[cfg(not(feature = "compact"))]
12use crate::table::{get_small_f32_power, get_small_f64_power, get_small_int_power};
13#[cfg(feature = "f16")]
14use lexical_util::bf16::bf16;
15use lexical_util::extended_float::ExtendedFloat;
16#[cfg(feature = "f16")]
17use lexical_util::f16::f16;
18use lexical_util::num::{AsCast, Float};
19
20/// Alias with ~80 bits of precision, 64 for the mantissa and 16 for exponent.
21/// This exponent is biased, and if the exponent is negative, it represents
22/// a value with a bias of `i32::MIN + F::EXPONENT_BIAS`.
23pub type ExtendedFloat80 = ExtendedFloat<u64>;
24
25/// Helper trait to add more float characteristics for parsing floats.
26pub trait RawFloat: Float + ExactFloat + MaxDigits {
27    // Maximum mantissa for the fast-path (`1 << 53` for f64).
28    const MAX_MANTISSA_FAST_PATH: u64 = 2_u64 << Self::MANTISSA_SIZE;
29
30    // Largest exponent value `(1 << EXP_BITS) - 1`.
31    const INFINITE_POWER: i32 = Self::MAX_EXPONENT + Self::EXPONENT_BIAS;
32
33    /// Minimum exponent that for a fast path case, or `-⌊(MANTISSA_SIZE+1)/log2(r)⌋`
34    /// where `r` is the radix with powers-of-two removed.
35    #[inline(always)]
36    fn min_exponent_fast_path(radix: u32) -> i64 {
37        Self::exponent_limit(radix).0
38    }
39
40    /// Maximum exponent that for a fast path case, or `⌊(MANTISSA_SIZE+1)/log2(r)⌋`
41    /// where `r` is the radix with powers-of-two removed.
42    #[inline(always)]
43    fn max_exponent_fast_path(radix: u32) -> i64 {
44        Self::exponent_limit(radix).1
45    }
46
47    // Maximum exponent that can be represented for a disguised-fast path case.
48    // This is `max_exponent_fast_path(radix) + ⌊(MANTISSA_SIZE+1)/log2(radix)⌋`
49    #[inline(always)]
50    fn max_exponent_disguised_fast_path(radix: u32) -> i64 {
51        Self::max_exponent_fast_path(radix) + Self::mantissa_limit(radix)
52    }
53
54    /// Get a small power-of-radix for fast-path multiplication.
55    ///
56    /// # Safety
57    ///
58    /// Safe as long as the exponent is smaller than the table size.
59    unsafe fn pow_fast_path(exponent: usize, radix: u32) -> Self;
60
61    /// Get a small, integral power-of-radix for fast-path multiplication.
62    ///
63    /// # Safety
64    ///
65    /// Safe as long as the exponent is smaller than the table size.
66    #[inline(always)]
67    unsafe fn int_pow_fast_path(exponent: usize, radix: u32) -> u64 {
68        // SAFETY: safe as long as the exponent is smaller than the radix table.
69        #[cfg(not(feature = "compact"))]
70        return unsafe { get_small_int_power(exponent, radix) };
71
72        #[cfg(feature = "compact")]
73        return (radix as u64).wrapping_pow(exponent as u32);
74    }
75}
76
77impl RawFloat for f32 {
78    #[inline(always)]
79    unsafe fn pow_fast_path(exponent: usize, radix: u32) -> Self {
80        // SAFETY: safe as long as the exponent is smaller than the radix table.
81        #[cfg(not(feature = "compact"))]
82        return unsafe { get_small_f32_power(exponent, radix) };
83
84        #[cfg(feature = "compact")]
85        return powf(radix as f32, exponent as f32);
86    }
87}
88
89impl RawFloat for f64 {
90    #[inline(always)]
91    unsafe fn pow_fast_path(exponent: usize, radix: u32) -> Self {
92        // SAFETY: safe as long as the exponent is smaller than the radix table.
93        #[cfg(not(feature = "compact"))]
94        return unsafe { get_small_f64_power(exponent, radix) };
95
96        #[cfg(feature = "compact")]
97        return powd(radix as f64, exponent as f64);
98    }
99}
100
101#[cfg(feature = "f16")]
102impl RawFloat for f16 {
103    #[inline(always)]
104    unsafe fn pow_fast_path(_: usize, _: u32) -> Self {
105        unimplemented!()
106    }
107}
108
109#[cfg(feature = "f16")]
110impl RawFloat for bf16 {
111    #[inline(always)]
112    unsafe fn pow_fast_path(_: usize, _: u32) -> Self {
113        unimplemented!()
114    }
115}
116
117/// Helper trait to add more float characteristics for the Eisel-Lemire algorithm.
118pub trait LemireFloat: RawFloat {
119    // Round-to-even only happens for negative values of q
120    // when q ≥ −4 in the 64-bit case and when q ≥ −17 in
121    // the 32-bitcase.
122    //
123    // When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we
124    // have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have
125    // 5^q ≤ 2m+1 ≤ 2^25 or q ≤ 10.
126    //
127    // When q < 0, we have w ≥ (2m+1)×5^−q. We must have that w < 2^64
128    // so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case)
129    // or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64
130    // (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11
131    // or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bitcase).
132    //
133    // Thus we have that we only need to round ties to even when
134    // we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10]
135    // (in the 32-bit case). In both cases,the power of five(5^|q|)
136    // fits in a 64-bit word.
137    const MIN_EXPONENT_ROUND_TO_EVEN: i32;
138    const MAX_EXPONENT_ROUND_TO_EVEN: i32;
139
140    /// Minimum normal exponent value `-(1 << (EXPONENT_SIZE - 1)) + 1`.
141    const MINIMUM_EXPONENT: i32;
142
143    /// Smallest decimal exponent for a non-zero value.
144    const SMALLEST_POWER_OF_TEN: i32;
145
146    /// Largest decimal exponent for a non-infinite value.
147    const LARGEST_POWER_OF_TEN: i32;
148}
149
150impl LemireFloat for f32 {
151    const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17;
152    const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
153    const MINIMUM_EXPONENT: i32 = -127;
154    const SMALLEST_POWER_OF_TEN: i32 = -65;
155    const LARGEST_POWER_OF_TEN: i32 = 38;
156}
157
158impl LemireFloat for f64 {
159    const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -4;
160    const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23;
161    const MINIMUM_EXPONENT: i32 = -1023;
162    const SMALLEST_POWER_OF_TEN: i32 = -342;
163    const LARGEST_POWER_OF_TEN: i32 = 308;
164}
165
166#[cfg(feature = "f16")]
167impl LemireFloat for f16 {
168    const MIN_EXPONENT_ROUND_TO_EVEN: i32 = 0;
169    const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 0;
170    const MINIMUM_EXPONENT: i32 = 0;
171    const SMALLEST_POWER_OF_TEN: i32 = 0;
172    const LARGEST_POWER_OF_TEN: i32 = 0;
173}
174
175#[cfg(feature = "f16")]
176impl LemireFloat for bf16 {
177    const MIN_EXPONENT_ROUND_TO_EVEN: i32 = 0;
178    const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 0;
179    const MINIMUM_EXPONENT: i32 = 0;
180    const SMALLEST_POWER_OF_TEN: i32 = 0;
181    const LARGEST_POWER_OF_TEN: i32 = 0;
182}
183
184#[inline(always)]
185#[cfg(all(feature = "std", feature = "compact"))]
186pub fn powf(x: f32, y: f32) -> f32 {
187    x.powf(y)
188}
189
190#[inline(always)]
191#[cfg(all(feature = "std", feature = "compact"))]
192pub fn powd(x: f64, y: f64) -> f64 {
193    x.powf(y)
194}
195
196/// Converts an `ExtendedFloat` to the closest machine float type.
197#[inline(always)]
198pub fn extended_to_float<F: Float>(x: ExtendedFloat80) -> F {
199    let mut word = x.mant;
200    word |= (x.exp as u64) << F::MANTISSA_SIZE;
201    F::from_bits(F::Unsigned::as_cast(word))
202}