#![cfg(feature = "power-of-two")]
#![doc(hidden)]
#[cfg(not(feature = "compact"))]
use lexical_parse_integer::algorithm;
use lexical_util::digit::char_to_valid_digit_const;
use lexical_util::format::NumberFormat;
use lexical_util::iterator::{AsBytes, DigitsIter};
use lexical_util::step::u64_step;
use crate::float::{ExtendedFloat80, RawFloat};
use crate::mask::lower_n_halfway;
use crate::number::Number;
use crate::shared;
#[cfg_attr(not(feature = "compact"), inline(always))]
pub fn binary<F: RawFloat, const FORMAT: u128>(num: &Number, lossy: bool) -> ExtendedFloat80 {
let format = NumberFormat::<{ FORMAT }> {};
debug_assert!(
matches!(format.radix(), 2 | 4 | 8 | 16 | 32),
"algorithm requires a power-of-two"
);
let fp_zero = ExtendedFloat80 {
mant: 0,
exp: 0,
};
let ctlz = num.mantissa.leading_zeros();
let mantissa = num.mantissa << ctlz;
let power2 = shared::calculate_power2::<F, FORMAT>(num.exponent, ctlz);
if -power2 + 1 >= 64 {
return fp_zero;
}
let shift = shared::calculate_shift::<F>(power2);
let last_bit = 1u64 << shift;
let truncated = last_bit - 1;
let halfway = lower_n_halfway(shift as u64);
let is_even = mantissa & last_bit == 0;
let is_halfway = mantissa & truncated == halfway;
if !lossy && is_even && is_halfway && num.many_digits {
return ExtendedFloat80 {
mant: mantissa,
exp: power2 + shared::INVALID_FP,
};
}
let is_above = mantissa & truncated > halfway;
let round_up = is_above || (!is_even && is_halfway);
let mut fp = ExtendedFloat80 {
mant: mantissa,
exp: power2,
};
shared::round::<F, _>(&mut fp, |f, s| {
shared::round_nearest_tie_even(f, s, |_, _, _| round_up);
});
fp
}
#[cfg_attr(not(feature = "compact"), inline(always))]
#[allow(unused_mut)]
pub fn parse_u64_digits<'a, Iter, const FORMAT: u128>(
mut iter: Iter,
mantissa: &mut u64,
step: &mut usize,
overflowed: &mut bool,
zero: &mut bool,
) where
Iter: DigitsIter<'a>,
{
let format = NumberFormat::<{ FORMAT }> {};
let radix = format.radix() as u64;
#[cfg(not(feature = "compact"))]
if can_try_parse_multidigit!(iter, radix) {
debug_assert!(radix < 16, "larger radices will wrap on radix^8");
let radix8 = format.radix8() as u64;
while *step > 8 {
if let Some(v) = algorithm::try_parse_8digits::<u64, _, FORMAT>(&mut iter) {
*mantissa = mantissa.wrapping_mul(radix8).wrapping_add(v);
*step -= 8;
} else {
break;
}
}
}
for &c in iter {
let digit = char_to_valid_digit_const(c, radix as u32);
if !*overflowed {
let result = mantissa.checked_mul(radix).and_then(|x| x.checked_add(digit as u64));
if let Some(mant) = result {
*mantissa = mant;
} else {
*overflowed = true;
*zero &= digit == 0;
}
} else {
*zero &= digit == 0;
}
*step = step.saturating_sub(1);
}
}
pub fn slow_binary<F: RawFloat, const FORMAT: u128>(num: Number) -> ExtendedFloat80 {
let format = NumberFormat::<{ FORMAT }> {};
let radix = format.radix();
debug_assert!(matches!(radix, 2 | 4 | 8 | 16 | 32), "algorithm requires a power-of-two");
let mut mantissa = 0_u64;
let mut overflow = false;
let mut zero = true;
let mut step = u64_step(radix);
let mut integer = num.integer.bytes::<FORMAT>();
integer.integer_iter().skip_zeros();
parse_u64_digits::<_, FORMAT>(
integer.integer_iter(),
&mut mantissa,
&mut step,
&mut overflow,
&mut zero,
);
if let Some(fraction) = num.fraction {
let mut fraction = fraction.bytes::<FORMAT>();
if mantissa == 0 {
fraction.fraction_iter().skip_zeros();
}
parse_u64_digits::<_, FORMAT>(
fraction.fraction_iter(),
&mut mantissa,
&mut step,
&mut overflow,
&mut zero,
);
}
let ctlz = mantissa.leading_zeros();
mantissa <<= ctlz;
let power2 = shared::calculate_power2::<F, FORMAT>(num.exponent, ctlz);
let mut fp = ExtendedFloat80 {
mant: mantissa,
exp: power2,
};
shared::round::<F, _>(&mut fp, |f, s| {
shared::round_nearest_tie_even(f, s, |_, _, _| !zero);
});
fp
}