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