use super::bignum::*;
use super::digit::*;
use super::exponent::*;
use super::float::*;
use super::math::*;
use super::num::*;
use super::rounding::*;
use crate::lib::{cmp, mem};
fn parse_mantissa<'a, F, Iter>(mut iter: Iter) -> Bigint
where
F: Float,
Iter: Iterator<Item = &'a u8> + Clone,
{
let small_powers = POW10_LIMB;
let step = small_powers.len() - 2;
let max_digits = F::MAX_DIGITS - 1;
let mut counter = 0;
let mut value: Limb = 0;
let mut i: usize = 0;
let mut result = Bigint::default();
while let Some(&digit) = iter.next() {
if counter == step {
result.imul_small(small_powers[counter]);
result.iadd_small(value);
counter = 0;
value = 0;
}
value *= 10;
value += as_limb(to_digit(digit).unwrap());
i += 1;
counter += 1;
if i == max_digits {
break;
}
}
if counter != 0 {
result.imul_small(small_powers[counter]);
result.iadd_small(value);
}
let is_consumed = iter.count() == 0;
if !is_consumed {
result.imul_small(10);
result.iadd_small(1);
}
result
}
#[inline]
pub(super) fn b_extended<F: Float>(f: F) -> ExtendedFloat {
ExtendedFloat::from_float(f)
}
#[inline]
pub(super) fn bh_extended<F: Float>(f: F) -> ExtendedFloat {
let b = b_extended(f);
ExtendedFloat {
mant: (b.mant << 1) + 1,
exp: b.exp - 1,
}
}
#[inline]
fn round_nearest_tie_even(fp: &mut ExtendedFloat, shift: i32, is_truncated: bool) {
let (mut is_above, mut is_halfway) = round_nearest(fp, shift);
if is_halfway && is_truncated {
is_above = true;
is_halfway = false;
}
tie_even(fp, is_above, is_halfway);
}
fn large_atof<'a, F, Iter>(iter: Iter, exponent: i32) -> F
where
F: Float,
Iter: Iterator<Item = &'a u8> + Clone,
{
let bits = mem::size_of::<u64>() * 8;
let mut bigmant = parse_mantissa::<F, _>(iter);
bigmant.imul_pow10(exponent.as_u32());
let (mant, is_truncated) = bigmant.hi64();
let exp = bigmant.bit_length().as_i32() - bits.as_i32();
let mut fp = ExtendedFloat {
mant,
exp,
};
fp.round_to_native::<F, _>(|fp, shift| round_nearest_tie_even(fp, shift, is_truncated));
into_float(fp)
}
fn small_atof<'a, F, Iter>(iter: Iter, exponent: i32, f: F) -> F
where
F: Float,
Iter: Iterator<Item = &'a u8> + Clone,
{
let mut real_digits = parse_mantissa::<F, _>(iter);
let real_exp = exponent;
debug_assert!(real_exp < 0);
let theor = bh_extended(f);
let mut theor_digits = Bigint::from_u64(theor.mant);
let theor_exp = theor.exp;
let binary_exp = theor_exp - real_exp;
let halfradix_exp = -real_exp;
let radix_exp = 0;
if halfradix_exp != 0 {
theor_digits.imul_pow5(halfradix_exp.as_u32());
}
if radix_exp != 0 {
theor_digits.imul_pow10(radix_exp.as_u32());
}
if binary_exp > 0 {
theor_digits.imul_pow2(binary_exp.as_u32());
} else if binary_exp < 0 {
real_digits.imul_pow2((-binary_exp).as_u32());
}
match real_digits.compare(&theor_digits) {
cmp::Ordering::Greater => f.next_positive(),
cmp::Ordering::Less => f,
cmp::Ordering::Equal => f.round_positive_even(),
}
}
pub(crate) fn bhcomp<'a, F, Iter1, Iter2>(b: F, integer: Iter1, fraction: Iter2, exponent: i32) -> F
where
F: Float,
Iter1: Iterator<Item = &'a u8> + Clone,
Iter2: Iterator<Item = &'a u8> + Clone,
{
let integer_digits = integer.clone().count();
let fraction_digits = fraction.clone().count();
let digits_start = match integer_digits {
0 => fraction.clone().take_while(|&x| x == &b'0').count(),
_ => 0,
};
let sci_exp = scientific_exponent(exponent, integer_digits, digits_start);
let count = F::MAX_DIGITS.min(integer_digits + fraction_digits - digits_start);
let scaled_exponent = sci_exp + 1 - count.as_i32();
let iter = integer.chain(fraction).skip(digits_start);
if scaled_exponent >= 0 {
large_atof(iter, scaled_exponent)
} else {
small_atof(iter, scaled_exponent, b)
}
}