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(feature = "f16")]
9use lexical_util::bf16::bf16;
10use lexical_util::extended_float::ExtendedFloat;
11#[cfg(feature = "f16")]
12use lexical_util::f16::f16;
13use lexical_util::num::{AsCast, Float};
14
15#[cfg(all(not(feature = "std"), feature = "compact"))]
16use crate::libm::{powd, powf};
17use crate::limits::{ExactFloat, MaxDigits};
18#[cfg(not(feature = "compact"))]
19use crate::table::{get_small_f32_power, get_small_f64_power, get_small_int_power};
20
21/// Alias with ~80 bits of precision, 64 for the mantissa and 16 for exponent.
22/// This exponent is biased, and if the exponent is negative, it represents
23/// a value with a bias of `i32::MIN + F::EXPONENT_BIAS`.
24pub type ExtendedFloat80 = ExtendedFloat<u64>;
25
26/// Helper trait to add more float characteristics for parsing floats.
27pub trait RawFloat: Float + ExactFloat + MaxDigits {
28    // Maximum mantissa for the fast-path (`1 << 53` for f64).
29    const MAX_MANTISSA_FAST_PATH: u64 = 2_u64 << Self::MANTISSA_SIZE;
30
31    // Largest exponent value `(1 << EXP_BITS) - 1`.
32    const INFINITE_POWER: i32 = Self::MAX_EXPONENT + Self::EXPONENT_BIAS;
33
34    /// Minimum exponent that for a fast path case, or
35    /// `-⌊(MANTISSA_SIZE+1)/log2(r)⌋` where `r` is the radix with
36    /// powers-of-two removed.
37    #[must_use]
38    #[inline(always)]
39    fn min_exponent_fast_path(radix: u32) -> i64 {
40        Self::exponent_limit(radix).0
41    }
42
43    /// Maximum exponent that for a fast path case, or
44    /// `⌊(MANTISSA_SIZE+1)/log2(r)⌋` where `r` is the radix with
45    /// powers-of-two removed.
46    #[must_use]
47    #[inline(always)]
48    fn max_exponent_fast_path(radix: u32) -> i64 {
49        Self::exponent_limit(radix).1
50    }
51
52    // Maximum exponent that can be represented for a disguised-fast path case.
53    // This is `max_exponent_fast_path(radix) + ⌊(MANTISSA_SIZE+1)/log2(radix)⌋`
54    #[must_use]
55    #[inline(always)]
56    fn max_exponent_disguised_fast_path(radix: u32) -> i64 {
57        Self::max_exponent_fast_path(radix) + Self::mantissa_limit(radix)
58    }
59
60    /// Get a small power-of-radix for fast-path multiplication.
61    fn pow_fast_path(exponent: usize, radix: u32) -> Self;
62
63    /// Get a small, integral power-of-radix for fast-path multiplication.
64    #[must_use]
65    #[inline(always)]
66    fn int_pow_fast_path(exponent: usize, radix: u32) -> u64 {
67        // SAFETY: safe as long as the exponent is smaller than the radix table.
68        #[cfg(not(feature = "compact"))]
69        return get_small_int_power(exponent, radix);
70
71        #[cfg(feature = "compact")]
72        return (radix as u64).wrapping_pow(exponent as u32);
73    }
74}
75
76impl RawFloat for f32 {
77    #[inline(always)]
78    fn pow_fast_path(exponent: usize, radix: u32) -> Self {
79        // SAFETY: safe as long as the exponent is smaller than the radix table.
80        #[cfg(not(feature = "compact"))]
81        return get_small_f32_power(exponent, radix);
82
83        #[cfg(feature = "compact")]
84        return powf(radix as f32, exponent as f32);
85    }
86}
87
88impl RawFloat for f64 {
89    #[inline(always)]
90    fn pow_fast_path(exponent: usize, radix: u32) -> Self {
91        // SAFETY: safe as long as the exponent is smaller than the radix table.
92        #[cfg(not(feature = "compact"))]
93        return get_small_f64_power(exponent, radix);
94
95        #[cfg(feature = "compact")]
96        return powd(radix as f64, exponent as f64);
97    }
98}
99
100#[cfg(feature = "f16")]
101impl RawFloat for f16 {
102    #[inline(always)]
103    fn pow_fast_path(_: usize, _: u32) -> Self {
104        unimplemented!()
105    }
106}
107
108#[cfg(feature = "f16")]
109impl RawFloat for bf16 {
110    #[inline(always)]
111    fn pow_fast_path(_: usize, _: u32) -> Self {
112        unimplemented!()
113    }
114}
115
116/// Helper trait to add more float characteristics for the Eisel-Lemire
117/// 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#[must_use]
198#[inline(always)]
199pub fn extended_to_float<F: Float>(x: ExtendedFloat80) -> F {
200    let mut word = x.mant;
201    word |= (x.exp as u64) << F::MANTISSA_SIZE;
202    F::from_bits(F::Unsigned::as_cast(word))
203}