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        #[cfg(not(feature = "compact"))]
68        return get_small_int_power(exponent, radix);
69
70        #[cfg(feature = "compact")]
71        return (radix as u64).wrapping_pow(exponent as u32);
72    }
73}
74
75impl RawFloat for f32 {
76    #[inline(always)]
77    fn pow_fast_path(exponent: usize, radix: u32) -> Self {
78        #[cfg(not(feature = "compact"))]
79        return get_small_f32_power(exponent, radix);
80
81        #[cfg(feature = "compact")]
82        return powf(radix as f32, exponent as f32);
83    }
84}
85
86impl RawFloat for f64 {
87    #[inline(always)]
88    fn pow_fast_path(exponent: usize, radix: u32) -> Self {
89        #[cfg(not(feature = "compact"))]
90        return get_small_f64_power(exponent, radix);
91
92        #[cfg(feature = "compact")]
93        return powd(radix as f64, exponent as f64);
94    }
95}
96
97#[cfg(feature = "f16")]
98impl RawFloat for f16 {
99    #[inline(always)]
100    fn pow_fast_path(_: usize, _: u32) -> Self {
101        unimplemented!()
102    }
103}
104
105#[cfg(feature = "f16")]
106impl RawFloat for bf16 {
107    #[inline(always)]
108    fn pow_fast_path(_: usize, _: u32) -> Self {
109        unimplemented!()
110    }
111}
112
113/// Helper trait to add more float characteristics for the Eisel-Lemire
114/// algorithm.
115pub trait LemireFloat: RawFloat {
116    // Round-to-even only happens for negative values of q
117    // when `q ≥ −4` in the 64-bit case and when `q ≥ −17` in
118    // the 32-bitcase.
119    //
120    // When `q ≥ 0`,we have that `5^q ≤ 2m+1`. In the 64-bit case,we
121    // have `5^q ≤ 2m+1 ≤ 2^54` or `q ≤ 23`. In the 32-bit case,we have
122    // `5^q ≤ 2m+1 ≤ 2^25` or `q ≤ 10`.
123    //
124    // When q < 0, we have `w ≥ (2m+1)×5^−q`. We must have that `w < 2^64`
125    // so `(2m+1)×5^−q < 2^64`. We have that `2m+1 > 2^53` (64-bit case)
126    // or `2m+1 > 2^24` (32-bit case). Hence,we must have `2^53×5^−q < 2^64`
127    // (64-bit) and `2^24×5^−q < 2^64` (32-bit). Hence we have `5^−q < 2^11`
128    // or `q ≥ −4` (64-bit case) and `5^−q < 2^40` or `q ≥ −17` (32-bitcase).
129    //
130    // Thus we have that we only need to round ties to even when
131    // we have that `q ∈ [−4,23]` (in the 64-bit case) or `q∈[−17,10]`
132    // (in the 32-bit case). In both cases,the power of five (`5^|q|`)
133    // fits in a 64-bit word.
134    const MIN_EXPONENT_ROUND_TO_EVEN: i32;
135    const MAX_EXPONENT_ROUND_TO_EVEN: i32;
136
137    /// Minimum normal exponent value `-(1 << (EXPONENT_SIZE - 1)) + 1`.
138    const MINIMUM_EXPONENT: i32;
139
140    /// Smallest decimal exponent for a non-zero value.
141    const SMALLEST_POWER_OF_TEN: i32;
142
143    /// Largest decimal exponent for a non-infinite value.
144    const LARGEST_POWER_OF_TEN: i32;
145}
146
147impl LemireFloat for f32 {
148    const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17;
149    const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
150    const MINIMUM_EXPONENT: i32 = -127;
151    const SMALLEST_POWER_OF_TEN: i32 = -65;
152    const LARGEST_POWER_OF_TEN: i32 = 38;
153}
154
155impl LemireFloat for f64 {
156    const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -4;
157    const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23;
158    const MINIMUM_EXPONENT: i32 = -1023;
159    const SMALLEST_POWER_OF_TEN: i32 = -342;
160    const LARGEST_POWER_OF_TEN: i32 = 308;
161}
162
163#[cfg(feature = "f16")]
164impl LemireFloat for f16 {
165    const MIN_EXPONENT_ROUND_TO_EVEN: i32 = 0;
166    const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 0;
167    const MINIMUM_EXPONENT: i32 = 0;
168    const SMALLEST_POWER_OF_TEN: i32 = 0;
169    const LARGEST_POWER_OF_TEN: i32 = 0;
170}
171
172#[cfg(feature = "f16")]
173impl LemireFloat for bf16 {
174    const MIN_EXPONENT_ROUND_TO_EVEN: i32 = 0;
175    const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 0;
176    const MINIMUM_EXPONENT: i32 = 0;
177    const SMALLEST_POWER_OF_TEN: i32 = 0;
178    const LARGEST_POWER_OF_TEN: i32 = 0;
179}
180
181#[inline(always)]
182#[cfg(all(feature = "std", feature = "compact"))]
183pub fn powf(x: f32, y: f32) -> f32 {
184    x.powf(y)
185}
186
187#[inline(always)]
188#[cfg(all(feature = "std", feature = "compact"))]
189pub fn powd(x: f64, y: f64) -> f64 {
190    x.powf(y)
191}
192
193/// Converts an `ExtendedFloat` to the closest machine float type.
194#[must_use]
195#[inline(always)]
196pub fn extended_to_float<F: Float>(x: ExtendedFloat80) -> F {
197    let mut word = x.mant;
198    word |= (x.exp as u64) << F::MANTISSA_SIZE;
199    F::from_bits(F::Unsigned::as_cast(word))
200}