202 lines
6.5 KiB
Rust
202 lines
6.5 KiB
Rust
//! Parse byte iterators to float.
|
|
|
|
#![doc(hidden)]
|
|
|
|
#[cfg(feature = "compact")]
|
|
use crate::bellerophon::bellerophon;
|
|
use crate::extended_float::{extended_to_float, ExtendedFloat};
|
|
#[cfg(not(feature = "compact"))]
|
|
use crate::lemire::lemire;
|
|
use crate::num::Float;
|
|
use crate::number::Number;
|
|
use crate::slow::slow;
|
|
|
|
/// Try to parse the significant digits quickly.
|
|
///
|
|
/// This attempts a very quick parse, to deal with common cases.
|
|
///
|
|
/// * `integer` - Slice containing the integer digits.
|
|
/// * `fraction` - Slice containing the fraction digits.
|
|
#[inline]
|
|
fn parse_number_fast<'a, Iter1, Iter2>(
|
|
integer: Iter1,
|
|
fraction: Iter2,
|
|
exponent: i32,
|
|
) -> Option<Number>
|
|
where
|
|
Iter1: Iterator<Item = &'a u8>,
|
|
Iter2: Iterator<Item = &'a u8>,
|
|
{
|
|
let mut num = Number::default();
|
|
let mut integer_count: usize = 0;
|
|
let mut fraction_count: usize = 0;
|
|
for &c in integer {
|
|
integer_count += 1;
|
|
let digit = c - b'0';
|
|
num.mantissa = num.mantissa.wrapping_mul(10).wrapping_add(digit as u64);
|
|
}
|
|
for &c in fraction {
|
|
fraction_count += 1;
|
|
let digit = c - b'0';
|
|
num.mantissa = num.mantissa.wrapping_mul(10).wrapping_add(digit as u64);
|
|
}
|
|
|
|
if integer_count + fraction_count <= 19 {
|
|
// Can't overflow, since must be <= 19.
|
|
num.exponent = exponent.saturating_sub(fraction_count as i32);
|
|
Some(num)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Parse the significant digits of the float and adjust the exponent.
|
|
///
|
|
/// * `integer` - Slice containing the integer digits.
|
|
/// * `fraction` - Slice containing the fraction digits.
|
|
#[inline]
|
|
fn parse_number<'a, Iter1, Iter2>(mut integer: Iter1, mut fraction: Iter2, exponent: i32) -> Number
|
|
where
|
|
Iter1: Iterator<Item = &'a u8> + Clone,
|
|
Iter2: Iterator<Item = &'a u8> + Clone,
|
|
{
|
|
// NOTE: for performance, we do this in 2 passes:
|
|
if let Some(num) = parse_number_fast(integer.clone(), fraction.clone(), exponent) {
|
|
return num;
|
|
}
|
|
|
|
// Can only add 19 digits.
|
|
let mut num = Number::default();
|
|
let mut count = 0;
|
|
while let Some(&c) = integer.next() {
|
|
count += 1;
|
|
if count == 20 {
|
|
// Only the integer digits affect the exponent.
|
|
num.many_digits = true;
|
|
num.exponent = exponent.saturating_add(into_i32(1 + integer.count()));
|
|
return num;
|
|
} else {
|
|
let digit = c - b'0';
|
|
num.mantissa = num.mantissa * 10 + digit as u64;
|
|
}
|
|
}
|
|
|
|
// Skip leading fraction zeros.
|
|
// This is required otherwise we might have a 0 mantissa and many digits.
|
|
let mut fraction_count: usize = 0;
|
|
if count == 0 {
|
|
for &c in &mut fraction {
|
|
fraction_count += 1;
|
|
if c != b'0' {
|
|
count += 1;
|
|
let digit = c - b'0';
|
|
num.mantissa = num.mantissa * 10 + digit as u64;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for c in fraction {
|
|
fraction_count += 1;
|
|
count += 1;
|
|
if count == 20 {
|
|
num.many_digits = true;
|
|
// This can't wrap, since we have at most 20 digits.
|
|
// We've adjusted the exponent too high by `fraction_count - 1`.
|
|
// Note: -1 is due to incrementing this loop iteration, which we
|
|
// didn't use.
|
|
num.exponent = exponent.saturating_sub(fraction_count as i32 - 1);
|
|
return num;
|
|
} else {
|
|
let digit = c - b'0';
|
|
num.mantissa = num.mantissa * 10 + digit as u64;
|
|
}
|
|
}
|
|
|
|
// No truncated digits: easy.
|
|
// Cannot overflow: <= 20 digits.
|
|
num.exponent = exponent.saturating_sub(fraction_count as i32);
|
|
num
|
|
}
|
|
|
|
/// Parse float from extracted float components.
|
|
///
|
|
/// * `integer` - Cloneable, forward iterator over integer digits.
|
|
/// * `fraction` - Cloneable, forward iterator over integer digits.
|
|
/// * `exponent` - Parsed, 32-bit exponent.
|
|
///
|
|
/// # Preconditions
|
|
/// 1. The integer should not have leading zeros.
|
|
/// 2. The fraction should not have trailing zeros.
|
|
/// 3. All bytes in `integer` and `fraction` should be valid digits,
|
|
/// in the range [`b'0', b'9'].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Although passing garbage input will not cause memory safety issues,
|
|
/// it is very likely to cause a panic with a large number of digits, or
|
|
/// in debug mode. The big-integer arithmetic without the `alloc` feature
|
|
/// assumes a maximum, fixed-width input, which assumes at maximum a
|
|
/// value of `10^(769 + 342)`, or ~4000 bits of storage. Passing in
|
|
/// nonsensical digits may require up to ~6000 bits of storage, which will
|
|
/// panic when attempting to add it to the big integer. It is therefore
|
|
/// up to the caller to validate this input.
|
|
///
|
|
/// We cannot efficiently remove trailing zeros while only accepting a
|
|
/// forward iterator.
|
|
pub fn parse_float<'a, F, Iter1, Iter2>(integer: Iter1, fraction: Iter2, exponent: i32) -> F
|
|
where
|
|
F: Float,
|
|
Iter1: Iterator<Item = &'a u8> + Clone,
|
|
Iter2: Iterator<Item = &'a u8> + Clone,
|
|
{
|
|
// Parse the mantissa and attempt the fast and moderate-path algorithms.
|
|
let num = parse_number(integer.clone(), fraction.clone(), exponent);
|
|
// Try the fast-path algorithm.
|
|
if let Some(value) = num.try_fast_path() {
|
|
return value;
|
|
}
|
|
|
|
// Now try the moderate path algorithm.
|
|
let mut fp = moderate_path::<F>(&num);
|
|
if fp.exp < 0 {
|
|
// Undo the invalid extended float biasing.
|
|
fp.exp -= F::INVALID_FP;
|
|
fp = slow::<F, _, _>(num, fp, integer, fraction);
|
|
}
|
|
|
|
// Unable to correctly round the float using the fast or moderate algorithms.
|
|
// Fallback to a slower, but always correct algorithm. If we have
|
|
// lossy, we can't be here.
|
|
extended_to_float::<F>(fp)
|
|
}
|
|
|
|
/// Wrapper for different moderate-path algorithms.
|
|
/// A return exponent of `-1` indicates an invalid value.
|
|
#[inline]
|
|
pub fn moderate_path<F: Float>(num: &Number) -> ExtendedFloat {
|
|
#[cfg(not(feature = "compact"))]
|
|
return lemire::<F>(num);
|
|
|
|
#[cfg(feature = "compact")]
|
|
return bellerophon::<F>(num);
|
|
}
|
|
|
|
/// Convert usize into i32 without overflow.
|
|
///
|
|
/// This is needed to ensure when adjusting the exponent relative to
|
|
/// the mantissa we do not overflow for comically-long exponents.
|
|
#[inline]
|
|
fn into_i32(value: usize) -> i32 {
|
|
if value > i32::max_value() as usize {
|
|
i32::max_value()
|
|
} else {
|
|
value as i32
|
|
}
|
|
}
|
|
|
|
// Add digit to mantissa.
|
|
#[inline]
|
|
pub fn add_digit(value: u64, digit: u8) -> Option<u64> {
|
|
value.checked_mul(10)?.checked_add(digit as u64)
|
|
}
|