Coverage Report

Created: 2026-01-25 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/lexical-parse-float-1.0.6/src/float.rs
Line
Count
Source
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")]
9
use lexical_util::bf16::bf16;
10
use lexical_util::extended_float::ExtendedFloat;
11
#[cfg(feature = "f16")]
12
use lexical_util::f16::f16;
13
use lexical_util::num::{AsCast, Float};
14
15
#[cfg(all(not(feature = "std"), feature = "compact"))]
16
use crate::libm::{powd, powf};
17
use crate::limits::{ExactFloat, MaxDigits};
18
#[cfg(not(feature = "compact"))]
19
use 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`.
24
pub type ExtendedFloat80 = ExtendedFloat<u64>;
25
26
/// Helper trait to add more float characteristics for parsing floats.
27
pub 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
941
    fn min_exponent_fast_path(radix: u32) -> i64 {
40
941
        Self::exponent_limit(radix).0
41
941
    }
<f64 as lexical_parse_float::float::RawFloat>::min_exponent_fast_path
Line
Count
Source
39
941
    fn min_exponent_fast_path(radix: u32) -> i64 {
40
941
        Self::exponent_limit(radix).0
41
941
    }
Unexecuted instantiation: <_ as lexical_parse_float::float::RawFloat>::min_exponent_fast_path
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
1.44k
    fn max_exponent_fast_path(radix: u32) -> i64 {
49
1.44k
        Self::exponent_limit(radix).1
50
1.44k
    }
<f64 as lexical_parse_float::float::RawFloat>::max_exponent_fast_path
Line
Count
Source
48
1.44k
    fn max_exponent_fast_path(radix: u32) -> i64 {
49
1.44k
        Self::exponent_limit(radix).1
50
1.44k
    }
Unexecuted instantiation: <_ as lexical_parse_float::float::RawFloat>::max_exponent_fast_path
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
910
    fn max_exponent_disguised_fast_path(radix: u32) -> i64 {
57
910
        Self::max_exponent_fast_path(radix) + Self::mantissa_limit(radix)
58
910
    }
<f64 as lexical_parse_float::float::RawFloat>::max_exponent_disguised_fast_path
Line
Count
Source
56
910
    fn max_exponent_disguised_fast_path(radix: u32) -> i64 {
57
910
        Self::max_exponent_fast_path(radix) + Self::mantissa_limit(radix)
58
910
    }
Unexecuted instantiation: <_ as lexical_parse_float::float::RawFloat>::max_exponent_disguised_fast_path
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
68
    fn int_pow_fast_path(exponent: usize, radix: u32) -> u64 {
67
        #[cfg(not(feature = "compact"))]
68
68
        return get_small_int_power(exponent, radix);
69
70
        #[cfg(feature = "compact")]
71
        return (radix as u64).wrapping_pow(exponent as u32);
72
68
    }
<f64 as lexical_parse_float::float::RawFloat>::int_pow_fast_path
Line
Count
Source
66
68
    fn int_pow_fast_path(exponent: usize, radix: u32) -> u64 {
67
        #[cfg(not(feature = "compact"))]
68
68
        return get_small_int_power(exponent, radix);
69
70
        #[cfg(feature = "compact")]
71
        return (radix as u64).wrapping_pow(exponent as u32);
72
68
    }
Unexecuted instantiation: <_ as lexical_parse_float::float::RawFloat>::int_pow_fast_path
73
}
74
75
impl RawFloat for f32 {
76
    #[inline(always)]
77
0
    fn pow_fast_path(exponent: usize, radix: u32) -> Self {
78
        #[cfg(not(feature = "compact"))]
79
0
        return get_small_f32_power(exponent, radix);
80
81
        #[cfg(feature = "compact")]
82
        return powf(radix as f32, exponent as f32);
83
0
    }
84
}
85
86
impl RawFloat for f64 {
87
    #[inline(always)]
88
531
    fn pow_fast_path(exponent: usize, radix: u32) -> Self {
89
        #[cfg(not(feature = "compact"))]
90
531
        return get_small_f64_power(exponent, radix);
91
92
        #[cfg(feature = "compact")]
93
        return powd(radix as f64, exponent as f64);
94
531
    }
95
}
96
97
#[cfg(feature = "f16")]
98
impl RawFloat for f16 {
99
    #[inline(always)]
100
    fn pow_fast_path(_: usize, _: u32) -> Self {
101
        unimplemented!()
102
    }
103
}
104
105
#[cfg(feature = "f16")]
106
impl 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.
115
pub 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
147
impl 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
155
impl 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")]
164
impl 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")]
173
impl 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"))]
183
pub fn powf(x: f32, y: f32) -> f32 {
184
    x.powf(y)
185
}
186
187
#[inline(always)]
188
#[cfg(all(feature = "std", feature = "compact"))]
189
pub 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)]
196
443
pub fn extended_to_float<F: Float>(x: ExtendedFloat80) -> F {
197
443
    let mut word = x.mant;
198
443
    word |= (x.exp as u64) << F::MANTISSA_SIZE;
199
443
    F::from_bits(F::Unsigned::as_cast(word))
200
443
}
lexical_parse_float::float::extended_to_float::<f64>
Line
Count
Source
196
443
pub fn extended_to_float<F: Float>(x: ExtendedFloat80) -> F {
197
443
    let mut word = x.mant;
198
443
    word |= (x.exp as u64) << F::MANTISSA_SIZE;
199
443
    F::from_bits(F::Unsigned::as_cast(word))
200
443
}
Unexecuted instantiation: lexical_parse_float::float::extended_to_float::<_>