1cbd624adSopenharmony_ci//! Parse byte iterators to float.
2cbd624adSopenharmony_ci
3cbd624adSopenharmony_ci#![doc(hidden)]
4cbd624adSopenharmony_ci
5cbd624adSopenharmony_ci#[cfg(feature = "compact")]
6cbd624adSopenharmony_ciuse crate::bellerophon::bellerophon;
7cbd624adSopenharmony_ciuse crate::extended_float::{extended_to_float, ExtendedFloat};
8cbd624adSopenharmony_ci#[cfg(not(feature = "compact"))]
9cbd624adSopenharmony_ciuse crate::lemire::lemire;
10cbd624adSopenharmony_ciuse crate::num::Float;
11cbd624adSopenharmony_ciuse crate::number::Number;
12cbd624adSopenharmony_ciuse crate::slow::slow;
13cbd624adSopenharmony_ci
14cbd624adSopenharmony_ci/// Try to parse the significant digits quickly.
15cbd624adSopenharmony_ci///
16cbd624adSopenharmony_ci/// This attempts a very quick parse, to deal with common cases.
17cbd624adSopenharmony_ci///
18cbd624adSopenharmony_ci/// * `integer`     - Slice containing the integer digits.
19cbd624adSopenharmony_ci/// * `fraction`    - Slice containing the fraction digits.
20cbd624adSopenharmony_ci#[inline]
21cbd624adSopenharmony_cifn parse_number_fast<'a, Iter1, Iter2>(
22cbd624adSopenharmony_ci    integer: Iter1,
23cbd624adSopenharmony_ci    fraction: Iter2,
24cbd624adSopenharmony_ci    exponent: i32,
25cbd624adSopenharmony_ci) -> Option<Number>
26cbd624adSopenharmony_ciwhere
27cbd624adSopenharmony_ci    Iter1: Iterator<Item = &'a u8>,
28cbd624adSopenharmony_ci    Iter2: Iterator<Item = &'a u8>,
29cbd624adSopenharmony_ci{
30cbd624adSopenharmony_ci    let mut num = Number::default();
31cbd624adSopenharmony_ci    let mut integer_count: usize = 0;
32cbd624adSopenharmony_ci    let mut fraction_count: usize = 0;
33cbd624adSopenharmony_ci    for &c in integer {
34cbd624adSopenharmony_ci        integer_count += 1;
35cbd624adSopenharmony_ci        let digit = c - b'0';
36cbd624adSopenharmony_ci        num.mantissa = num.mantissa.wrapping_mul(10).wrapping_add(digit as u64);
37cbd624adSopenharmony_ci    }
38cbd624adSopenharmony_ci    for &c in fraction {
39cbd624adSopenharmony_ci        fraction_count += 1;
40cbd624adSopenharmony_ci        let digit = c - b'0';
41cbd624adSopenharmony_ci        num.mantissa = num.mantissa.wrapping_mul(10).wrapping_add(digit as u64);
42cbd624adSopenharmony_ci    }
43cbd624adSopenharmony_ci
44cbd624adSopenharmony_ci    if integer_count + fraction_count <= 19 {
45cbd624adSopenharmony_ci        // Can't overflow, since must be <= 19.
46cbd624adSopenharmony_ci        num.exponent = exponent.saturating_sub(fraction_count as i32);
47cbd624adSopenharmony_ci        Some(num)
48cbd624adSopenharmony_ci    } else {
49cbd624adSopenharmony_ci        None
50cbd624adSopenharmony_ci    }
51cbd624adSopenharmony_ci}
52cbd624adSopenharmony_ci
53cbd624adSopenharmony_ci/// Parse the significant digits of the float and adjust the exponent.
54cbd624adSopenharmony_ci///
55cbd624adSopenharmony_ci/// * `integer`     - Slice containing the integer digits.
56cbd624adSopenharmony_ci/// * `fraction`    - Slice containing the fraction digits.
57cbd624adSopenharmony_ci#[inline]
58cbd624adSopenharmony_cifn parse_number<'a, Iter1, Iter2>(mut integer: Iter1, mut fraction: Iter2, exponent: i32) -> Number
59cbd624adSopenharmony_ciwhere
60cbd624adSopenharmony_ci    Iter1: Iterator<Item = &'a u8> + Clone,
61cbd624adSopenharmony_ci    Iter2: Iterator<Item = &'a u8> + Clone,
62cbd624adSopenharmony_ci{
63cbd624adSopenharmony_ci    // NOTE: for performance, we do this in 2 passes:
64cbd624adSopenharmony_ci    if let Some(num) = parse_number_fast(integer.clone(), fraction.clone(), exponent) {
65cbd624adSopenharmony_ci        return num;
66cbd624adSopenharmony_ci    }
67cbd624adSopenharmony_ci
68cbd624adSopenharmony_ci    // Can only add 19 digits.
69cbd624adSopenharmony_ci    let mut num = Number::default();
70cbd624adSopenharmony_ci    let mut count = 0;
71cbd624adSopenharmony_ci    while let Some(&c) = integer.next() {
72cbd624adSopenharmony_ci        count += 1;
73cbd624adSopenharmony_ci        if count == 20 {
74cbd624adSopenharmony_ci            // Only the integer digits affect the exponent.
75cbd624adSopenharmony_ci            num.many_digits = true;
76cbd624adSopenharmony_ci            num.exponent = exponent.saturating_add(into_i32(1 + integer.count()));
77cbd624adSopenharmony_ci            return num;
78cbd624adSopenharmony_ci        } else {
79cbd624adSopenharmony_ci            let digit = c - b'0';
80cbd624adSopenharmony_ci            num.mantissa = num.mantissa * 10 + digit as u64;
81cbd624adSopenharmony_ci        }
82cbd624adSopenharmony_ci    }
83cbd624adSopenharmony_ci
84cbd624adSopenharmony_ci    // Skip leading fraction zeros.
85cbd624adSopenharmony_ci    // This is required otherwise we might have a 0 mantissa and many digits.
86cbd624adSopenharmony_ci    let mut fraction_count: usize = 0;
87cbd624adSopenharmony_ci    if count == 0 {
88cbd624adSopenharmony_ci        for &c in &mut fraction {
89cbd624adSopenharmony_ci            fraction_count += 1;
90cbd624adSopenharmony_ci            if c != b'0' {
91cbd624adSopenharmony_ci                count += 1;
92cbd624adSopenharmony_ci                let digit = c - b'0';
93cbd624adSopenharmony_ci                num.mantissa = num.mantissa * 10 + digit as u64;
94cbd624adSopenharmony_ci                break;
95cbd624adSopenharmony_ci            }
96cbd624adSopenharmony_ci        }
97cbd624adSopenharmony_ci    }
98cbd624adSopenharmony_ci    for c in fraction {
99cbd624adSopenharmony_ci        fraction_count += 1;
100cbd624adSopenharmony_ci        count += 1;
101cbd624adSopenharmony_ci        if count == 20 {
102cbd624adSopenharmony_ci            num.many_digits = true;
103cbd624adSopenharmony_ci            // This can't wrap, since we have at most 20 digits.
104cbd624adSopenharmony_ci            // We've adjusted the exponent too high by `fraction_count - 1`.
105cbd624adSopenharmony_ci            // Note: -1 is due to incrementing this loop iteration, which we
106cbd624adSopenharmony_ci            // didn't use.
107cbd624adSopenharmony_ci            num.exponent = exponent.saturating_sub(fraction_count as i32 - 1);
108cbd624adSopenharmony_ci            return num;
109cbd624adSopenharmony_ci        } else {
110cbd624adSopenharmony_ci            let digit = c - b'0';
111cbd624adSopenharmony_ci            num.mantissa = num.mantissa * 10 + digit as u64;
112cbd624adSopenharmony_ci        }
113cbd624adSopenharmony_ci    }
114cbd624adSopenharmony_ci
115cbd624adSopenharmony_ci    // No truncated digits: easy.
116cbd624adSopenharmony_ci    // Cannot overflow: <= 20 digits.
117cbd624adSopenharmony_ci    num.exponent = exponent.saturating_sub(fraction_count as i32);
118cbd624adSopenharmony_ci    num
119cbd624adSopenharmony_ci}
120cbd624adSopenharmony_ci
121cbd624adSopenharmony_ci/// Parse float from extracted float components.
122cbd624adSopenharmony_ci///
123cbd624adSopenharmony_ci/// * `integer`     - Cloneable, forward iterator over integer digits.
124cbd624adSopenharmony_ci/// * `fraction`    - Cloneable, forward iterator over integer digits.
125cbd624adSopenharmony_ci/// * `exponent`    - Parsed, 32-bit exponent.
126cbd624adSopenharmony_ci///
127cbd624adSopenharmony_ci/// # Preconditions
128cbd624adSopenharmony_ci/// 1. The integer should not have leading zeros.
129cbd624adSopenharmony_ci/// 2. The fraction should not have trailing zeros.
130cbd624adSopenharmony_ci/// 3. All bytes in `integer` and `fraction` should be valid digits,
131cbd624adSopenharmony_ci///     in the range [`b'0', b'9'].
132cbd624adSopenharmony_ci///
133cbd624adSopenharmony_ci/// # Panics
134cbd624adSopenharmony_ci///
135cbd624adSopenharmony_ci/// Although passing garbage input will not cause memory safety issues,
136cbd624adSopenharmony_ci/// it is very likely to cause a panic with a large number of digits, or
137cbd624adSopenharmony_ci/// in debug mode. The big-integer arithmetic without the `alloc` feature
138cbd624adSopenharmony_ci/// assumes a maximum, fixed-width input, which assumes at maximum a
139cbd624adSopenharmony_ci/// value of `10^(769 + 342)`, or ~4000 bits of storage. Passing in
140cbd624adSopenharmony_ci/// nonsensical digits may require up to ~6000 bits of storage, which will
141cbd624adSopenharmony_ci/// panic when attempting to add it to the big integer. It is therefore
142cbd624adSopenharmony_ci/// up to the caller to validate this input.
143cbd624adSopenharmony_ci///
144cbd624adSopenharmony_ci/// We cannot efficiently remove trailing zeros while only accepting a
145cbd624adSopenharmony_ci/// forward iterator.
146cbd624adSopenharmony_cipub fn parse_float<'a, F, Iter1, Iter2>(integer: Iter1, fraction: Iter2, exponent: i32) -> F
147cbd624adSopenharmony_ciwhere
148cbd624adSopenharmony_ci    F: Float,
149cbd624adSopenharmony_ci    Iter1: Iterator<Item = &'a u8> + Clone,
150cbd624adSopenharmony_ci    Iter2: Iterator<Item = &'a u8> + Clone,
151cbd624adSopenharmony_ci{
152cbd624adSopenharmony_ci    // Parse the mantissa and attempt the fast and moderate-path algorithms.
153cbd624adSopenharmony_ci    let num = parse_number(integer.clone(), fraction.clone(), exponent);
154cbd624adSopenharmony_ci    // Try the fast-path algorithm.
155cbd624adSopenharmony_ci    if let Some(value) = num.try_fast_path() {
156cbd624adSopenharmony_ci        return value;
157cbd624adSopenharmony_ci    }
158cbd624adSopenharmony_ci
159cbd624adSopenharmony_ci    // Now try the moderate path algorithm.
160cbd624adSopenharmony_ci    let mut fp = moderate_path::<F>(&num);
161cbd624adSopenharmony_ci    if fp.exp < 0 {
162cbd624adSopenharmony_ci        // Undo the invalid extended float biasing.
163cbd624adSopenharmony_ci        fp.exp -= F::INVALID_FP;
164cbd624adSopenharmony_ci        fp = slow::<F, _, _>(num, fp, integer, fraction);
165cbd624adSopenharmony_ci    }
166cbd624adSopenharmony_ci
167cbd624adSopenharmony_ci    // Unable to correctly round the float using the fast or moderate algorithms.
168cbd624adSopenharmony_ci    // Fallback to a slower, but always correct algorithm. If we have
169cbd624adSopenharmony_ci    // lossy, we can't be here.
170cbd624adSopenharmony_ci    extended_to_float::<F>(fp)
171cbd624adSopenharmony_ci}
172cbd624adSopenharmony_ci
173cbd624adSopenharmony_ci/// Wrapper for different moderate-path algorithms.
174cbd624adSopenharmony_ci/// A return exponent of `-1` indicates an invalid value.
175cbd624adSopenharmony_ci#[inline]
176cbd624adSopenharmony_cipub fn moderate_path<F: Float>(num: &Number) -> ExtendedFloat {
177cbd624adSopenharmony_ci    #[cfg(not(feature = "compact"))]
178cbd624adSopenharmony_ci    return lemire::<F>(num);
179cbd624adSopenharmony_ci
180cbd624adSopenharmony_ci    #[cfg(feature = "compact")]
181cbd624adSopenharmony_ci    return bellerophon::<F>(num);
182cbd624adSopenharmony_ci}
183cbd624adSopenharmony_ci
184cbd624adSopenharmony_ci/// Convert usize into i32 without overflow.
185cbd624adSopenharmony_ci///
186cbd624adSopenharmony_ci/// This is needed to ensure when adjusting the exponent relative to
187cbd624adSopenharmony_ci/// the mantissa we do not overflow for comically-long exponents.
188cbd624adSopenharmony_ci#[inline]
189cbd624adSopenharmony_cifn into_i32(value: usize) -> i32 {
190cbd624adSopenharmony_ci    if value > i32::max_value() as usize {
191cbd624adSopenharmony_ci        i32::max_value()
192cbd624adSopenharmony_ci    } else {
193cbd624adSopenharmony_ci        value as i32
194cbd624adSopenharmony_ci    }
195cbd624adSopenharmony_ci}
196cbd624adSopenharmony_ci
197cbd624adSopenharmony_ci// Add digit to mantissa.
198cbd624adSopenharmony_ci#[inline]
199cbd624adSopenharmony_cipub fn add_digit(value: u64, digit: u8) -> Option<u64> {
200cbd624adSopenharmony_ci    value.checked_mul(10)?.checked_add(digit as u64)
201cbd624adSopenharmony_ci}
202