#![allow(unused_imports)]
use lib::ptr;
use atoi;
use float::*;
use util::*;
use super::alias::*;
use super::cached::ModeratePathCache;
use super::bhcomp;
use super::exponent::*;
use super::small_powers::get_small_powers_64;
macro_rules! ltrim_0 {
($bytes:expr) => { ltrim_char_slice($bytes, b'0') };
}
macro_rules! rtrim_0 {
($bytes:expr) => { rtrim_char_slice($bytes, b'0') };
}
#[cfg_attr(test, derive(Debug))]
pub(super) struct FloatSlice<'a> {
integer: &'a [u8],
fraction: &'a [u8],
digits_start: usize,
digits_end: usize,
truncated: usize,
raw_exponent: i32,
}
impl<'a> FloatSlice<'a> {
#[inline]
pub(super) fn uninitialized() -> FloatSlice<'a> {
FloatSlice {
integer: &[],
fraction: &[],
digits_start: explicit_uninitialized(),
digits_end: explicit_uninitialized(),
truncated: explicit_uninitialized(),
raw_exponent: explicit_uninitialized(),
}
}
#[inline]
pub(super) fn integer_len(&self) -> usize {
self.integer.len()
}
#[inline]
pub(super) fn integer_digits(&self) -> usize {
self.integer_len()
}
#[inline]
pub(super) fn integer_iter(&self) -> SliceIter<u8> {
self.integer.iter()
}
#[inline]
pub(super) fn fraction_len(&self) -> usize {
self.digits_end
}
#[inline]
pub(super) fn fraction_digits(&self) -> usize {
self.fraction_len() - self.digits_start
}
#[inline]
pub(super) fn fraction_iter(&self) -> SliceIter<u8> {
self.fraction[self.digits_start..self.digits_end].iter()
}
#[inline]
pub(super) fn mantissa_digits(&self) -> usize {
self.integer_digits() + self.fraction_digits()
}
#[inline]
pub(super) fn mantissa_iter(&self) -> ChainedSliceIter<u8> {
self.integer_iter().chain(self.fraction_iter())
}
#[inline]
pub(super) fn truncated_digits(&self) -> usize {
let trailing = self.fraction.len() - self.digits_end;
match self.truncated > trailing {
true => self.truncated - trailing,
false => 0,
}
}
#[inline]
pub(super) fn mantissa_exponent(&self) -> i32 {
mantissa_exponent(self.raw_exponent, self.fraction_len(), self.truncated_digits())
}
#[inline]
pub(super) fn scientific_exponent(&self) -> i32 {
let fraction_start = match self.digits_start.is_zero() {
true => 0,
false => self.digits_start,
};
scientific_exponent(self.raw_exponent, self.integer_digits(), fraction_start)
}
}
#[inline]
fn adjust_truncated_mantissa<M>(mantissa: M, radix: u32, trimmed: usize, truncated: usize)
-> M
where M: Mantissa
{
if trimmed > truncated {
let base: M = as_cast(radix);
let pow: M = base.pow(as_cast(trimmed - truncated));
mantissa / pow
} else {
mantissa
}
}
#[inline]
fn parse_mantissa<'a, M>(radix: u32, mut bytes: &'a [u8])
-> (M, FloatSlice, &'a [u8], Option<&'a u8>)
where M: Mantissa
{
let mut mantissa: M = M::ZERO;
let mut slc = FloatSlice::uninitialized();
bytes = ltrim_0!(bytes).0;
let first = bytes.as_ptr();
let (len, truncated) = atoi::checked_positive(&mut mantissa, as_cast(radix), bytes);
bytes = &index!(bytes[len..]);
slc.integer = slice_from_span(first, len);
let has_fraction = Some(&b'.') == bytes.get(0);
if has_fraction && truncated.is_none() {
bytes = &index!(bytes[1..]);
let first = bytes.as_ptr();
if mantissa.is_zero() {
let trim = ltrim_0!(bytes);
bytes = trim.0;
slc.digits_start = trim.1;
} else {
slc.digits_start = 0;
}
let (len, truncated) = atoi::checked_positive(&mut mantissa, as_cast(radix), bytes);
let bytes = &index!(bytes[len..]);
slc.fraction = slice_from_span(first, len + slc.digits_start);
let trim = rtrim_0!(slc.fraction);
slc.digits_end = len + slc.digits_start - trim.1;
slc.truncated = truncated.map_or(0, |p| distance(p, bytes.as_ptr()));
mantissa = adjust_truncated_mantissa(mantissa, radix, trim.1, slc.truncated);
(mantissa, slc, bytes, truncated)
} else if has_fraction {
bytes = &index!(bytes[1..]);
let first = bytes.as_ptr();
let len = bytes.iter()
.take_while(|&&c| char_to_digit(c).as_u32() < radix)
.count();
bytes = &index!(bytes[len..]);
slc.digits_start = 0;
slc.fraction = slice_from_span(first, len);
let trim = rtrim_0!(slc.fraction);
slc.digits_end = len - trim.1;
slc.truncated = distance(truncated.unwrap(), bytes.as_ptr()) - 1;
mantissa = adjust_truncated_mantissa(mantissa, radix, trim.1, slc.truncated);
(mantissa, slc, bytes, truncated)
} else {
slc.digits_start = 0;
slc.fraction = slice_from_span(bytes.as_ptr(), 0);
slc.truncated = truncated.map_or(0, |p| distance(p, bytes.as_ptr()));
slc.digits_end = 0;
(mantissa, slc, bytes, truncated)
}
}
#[inline]
fn parse_float<'a, M>(radix: u32, bytes: &'a [u8])
-> (M, FloatSlice, &'a [u8], Option<&'a u8>)
where M: Mantissa
{
let (mantissa, mut slc, bytes, truncated) = parse_mantissa::<M>(radix, bytes);
let (raw_exponent, bytes) = parse_exponent(radix, bytes);
slc.raw_exponent = raw_exponent;
(mantissa, slc, bytes, truncated)
}
#[inline]
fn pow2_exponent(radix: u32) -> i32 {
match radix {
2 => 1,
4 => 2,
8 => 3,
16 => 4,
32 => 5,
_ => 0,
}
}
#[cfg(feature = "radix")]
#[inline]
fn is_halfway<F: FloatType>(mantissa: u64)
-> bool
{
let bit_length: i32 = 64 - mantissa.leading_zeros().as_i32();
let trailing_zeros: i32 = mantissa.trailing_zeros().as_i32();
bit_length - trailing_zeros == F::MANTISSA_SIZE + 2
}
#[cfg(feature = "radix")]
#[inline]
fn is_odd<F: FloatType>(mantissa: u64)
-> bool
{
let bit_length: i32 = 64 - mantissa.leading_zeros().as_i32();
let shift = bit_length - (F::MANTISSA_SIZE + 1);
if shift >= 0 {
let mask = 1u64 << shift;
mantissa & mask == mask
} else {
false
}
}
#[cfg(feature = "radix")]
#[inline]
fn pow2_fast_path<F>(mantissa: u64, radix: u32, pow2_exp: i32, exponent: i32)
-> F
where F: FloatType
{
debug_assert!(pow2_exp != 0, "Not a power of 2.");
let (min_exp, max_exp) = F::exponent_limit(radix);
let underflow_exp = min_exp - (65 / pow2_exp);
if exponent > max_exp {
F::INFINITY
} else if exponent < underflow_exp{
F::ZERO
} else if exponent < min_exp {
let remainder = exponent - min_exp;
let float: F = as_cast(mantissa);
let float = float.pow2(pow2_exp * remainder).pow2(pow2_exp * min_exp);
float
} else {
let float: F = as_cast(mantissa);
let float = float.pow2(pow2_exp * exponent);
float
}
}
#[inline]
fn fast_path<F>(mantissa: u64, radix: u32, exponent: i32)
-> (F, bool)
where F: FloatType
{
debug_assert_radix!(radix);
debug_assert!(pow2_exponent(radix) == 0, "Cannot use `fast_path` with a power of 2.");
let (min_exp, max_exp) = F::exponent_limit(radix);
let shift_exp = F::mantissa_limit(radix);
let mantissa_size = F::MANTISSA_SIZE + 1;
if mantissa >> mantissa_size != 0 {
(F::ZERO, false)
} else {
if exponent == 0 {
let float: F = as_cast(mantissa);
(float, true)
} else if exponent >= min_exp && exponent <= max_exp {
let float: F = as_cast(mantissa);
let float = float.pow(radix, exponent);
(float, true)
} else if exponent >= 0 && exponent <= max_exp + shift_exp {
let small_powers = get_small_powers_64(radix);
let shift = exponent - max_exp;
let power = small_powers[shift.as_usize()];
mantissa.checked_mul(power)
.map_or((F::ZERO, false), |v| {
if v >> mantissa_size != 0 {
(F::ZERO, false)
} else {
let float: F = as_cast(v);
let float = float.pow(radix, max_exp);
(float, true)
}
})
} else {
(F::ZERO, false)
}
}
}
pub trait FloatErrors: Mantissa {
fn error_scale() -> u32;
fn error_halfscale() -> u32;
fn error_is_accurate<F: Float>(count: u32, fp: &ExtendedFloat<Self>, kind: RoundingKind) -> bool;
}
#[inline]
fn nearest_error_is_accurate(errors: u64, fp: &ExtendedFloat<u64>, extrabits: u64)
-> bool
{
if extrabits == 65 {
!fp.mant.overflowing_add(errors).1
} else {
let mask: u64 = lower_n_mask(extrabits);
let extra: u64 = fp.mant & mask;
let halfway: u64 = lower_n_halfway(extrabits);
let cmp1 = halfway.wrapping_sub(errors) < extra;
let cmp2 = extra < halfway.wrapping_add(errors);
!(cmp1 && cmp2)
}
}
#[cfg(feature = "rounding")]
#[inline]
fn toward_error_is_accurate(errors: u64, fp: &ExtendedFloat<u64>, extrabits: u64)
-> bool
{
if extrabits == 65 {
true
} else {
let mask: u64 = lower_n_mask(extrabits);
let extra: u64 = fp.mant & mask;
if extrabits == 64 {
let cmp1 = extra.checked_sub(errors).is_none();
let cmp2 = extra.checked_add(errors).is_none();
cmp1 || cmp2
} else {
let fullway: u64 = nth_bit(extrabits);
let cmp1 = fullway.wrapping_sub(errors) < extra;
let cmp2 = extra < fullway.wrapping_add(errors);
!(cmp1 && cmp2)
}
}
}
impl FloatErrors for u64 {
#[inline]
fn error_scale() -> u32 {
8
}
#[inline]
fn error_halfscale() -> u32 {
u64::error_scale() / 2
}
#[inline]
#[allow(unused_variables)]
fn error_is_accurate<F: Float>(count: u32, fp: &ExtendedFloat<u64>, kind: RoundingKind)
-> bool
{
let bias = -(F::EXPONENT_BIAS - F::MANTISSA_SIZE);
let denormal_exp = bias - 63;
let extrabits = match fp.exp <= denormal_exp {
true => 64 - F::MANTISSA_SIZE + denormal_exp - fp.exp,
false => 63 - F::MANTISSA_SIZE,
};
let extrabits = extrabits.as_u64();
let errors = count.as_u64();
if extrabits > 65 {
return true;
}
#[cfg(not(feature = "rounding"))] {
nearest_error_is_accurate(errors, fp, extrabits)
}
#[cfg(feature = "rounding")] {
if is_nearest(kind) {
nearest_error_is_accurate(errors, fp, extrabits)
} else {
toward_error_is_accurate(errors, fp, extrabits)
}
}
}
}
#[cfg(has_i128)]
impl FloatErrors for u128 {
#[inline]
fn error_scale() -> u32 {
0
}
#[inline]
fn error_halfscale() -> u32 {
0
}
#[inline]
fn error_is_accurate<F: Float>(_: u32, _: &ExtendedFloat<u128>, _: RoundingKind) -> bool {
true
}
}
#[inline]
fn multiply_exponent_extended<F, M>(fp: &mut ExtendedFloat<M>, radix: u32, exponent: i32, truncated: bool, kind: RoundingKind)
-> bool
where M: FloatErrors,
F: FloatRounding<M>,
ExtendedFloat<M>: ModeratePathCache<M>
{
let powers = ExtendedFloat::<M>::get_powers(radix);
let exponent = exponent + powers.bias;
let small_index = exponent % powers.step;
let large_index = exponent / powers.step;
if exponent < 0 {
fp.mant = M::ZERO;
true
} else if large_index as usize >= powers.large.len() {
fp.mant = M::ONE << 63;
fp.exp = 0x7FF;
true
} else {
let mut errors: u32 = 0;
if truncated {
errors += M::error_halfscale();
}
match fp.mant.overflowing_mul(powers.get_small_int(small_index.as_usize())) {
(_, true) => {
fp.normalize();
fp.imul(&powers.get_small(small_index.as_usize()));
errors += M::error_halfscale();
},
(mant, false) => {
fp.mant = mant;
fp.normalize();
},
}
fp.imul(&powers.get_large(large_index.as_usize()));
if errors > 0 {
errors += 1;
}
errors += M::error_halfscale();
let shift = fp.normalize();
errors <<= shift;
M::error_is_accurate::<F>(errors, &fp, kind)
}
}
#[inline]
pub(super) fn moderate_path<F, M>(mantissa: M, radix: u32, exponent: i32, truncated: bool, kind: RoundingKind)
-> (ExtendedFloat<M>, bool)
where M: FloatErrors,
F: FloatRounding<M> + StablePower,
ExtendedFloat<M>: ModeratePathCache<M>
{
let mut fp = ExtendedFloat { mant: mantissa, exp: 0 };
let valid = multiply_exponent_extended::<F, M>(&mut fp, radix, exponent, truncated, kind);
(fp, valid)
}
#[cfg(feature = "radix")]
#[inline]
fn pow2_to_native<'a, F>(radix: u32, pow2_exp: i32, bytes: &'a [u8], sign: Sign)
-> (F, &'a [u8])
where F: FloatType
{
let (mut mantissa, slc, bytes, truncated) = parse_float::<u64>(radix, bytes);
let kind = global_rounding(sign);
let mantissa_size = F::MANTISSA_SIZE + 1;
if truncated.is_some() {
if kind != RoundingKind::Downward {
let bytes = slice_from_range(truncated.unwrap(), bytes.as_ptr());
let count = bytes.iter().take_while(|&&c| c == b'0' || c == b'.').count();
let bytes = &bytes[count..];
let is_truncated = bytes.get(0).map_or(false, |&c| char_to_digit(c).as_u32() < radix);
if cfg!(feature = "rounding") || kind == RoundingKind::NearestTieEven {
if is_halfway::<F>(mantissa) && is_odd::<F>(mantissa) {
mantissa += 1;
}
} else if kind == RoundingKind::NearestTieAwayZero {
if is_halfway::<F>(mantissa) {
mantissa += 1;
}
} else {
if is_truncated {
mantissa += 1;
}
}
}
let exponent = slc.mantissa_exponent().saturating_mul(pow2_exp);
let fp = ExtendedFloat { mant: mantissa, exp: exponent };
(fp.into_rounded_float_impl::<F>(kind), bytes)
} else if mantissa >> mantissa_size != 0 {
let exponent = slc.mantissa_exponent().saturating_mul(pow2_exp);
let fp = ExtendedFloat { mant: mantissa, exp: exponent };
(fp.into_rounded_float_impl::<F>(kind), bytes)
} else {
let float = pow2_fast_path(mantissa, radix, pow2_exp, slc.mantissa_exponent());
(float, bytes)
}
}
#[inline]
fn pown_to_native<'a, F>(radix: u32, bytes: &'a [u8], lossy: bool, sign: Sign)
-> (F, &'a [u8])
where F: FloatType
{
let (mantissa, slc, bytes, _) = parse_float::<u64>(radix, bytes);
let exponent = slc.mantissa_exponent();
let kind = global_rounding(sign);
if mantissa == 0 {
return (F::ZERO, bytes);
} else if exponent > 0x40000000 {
return (F::INFINITY, bytes);
} else if exponent < -0x40000000 {
return (F::ZERO, bytes);
} else if slc.truncated.is_zero() {
let (float, valid) = fast_path::<F>(mantissa, radix, exponent);
if valid {
return (float, bytes);
}
}
let (fp, valid) = moderate_path::<F, _>(mantissa, radix, exponent, slc.truncated != 0, kind);
if valid || lossy {
let float = fp.into_rounded_float_impl::<F>(kind);
return (float, bytes);
}
let b = fp.into_rounded_float_impl::<F>(RoundingKind::Downward);
if b.is_special() {
return (b, bytes);
} else {
let float = bhcomp::atof(slc, radix, b, kind);
return (float, bytes);
}
}
#[inline]
fn to_native<F>(radix: u32, bytes: &[u8], lossy: bool, sign: Sign)
-> (F, usize)
where F: FloatType
{
#[cfg(not(feature = "radix"))] {
let (f, slc) = pown_to_native(radix, bytes, lossy, sign);
(f, bytes.len() - slc.len())
}
#[cfg(feature = "radix")] {
let pow2_exp = pow2_exponent(radix);
let (f, slc) = match pow2_exp {
0 => pown_to_native(radix, bytes, lossy, sign),
_ => pow2_to_native(radix, pow2_exp, bytes, sign),
};
(f, bytes.len() - slc.len())
}
}
#[inline]
pub(crate) fn atof(radix: u32, bytes: &[u8], sign: Sign)
-> (f32, usize)
{
to_native::<f32>(radix, bytes, false, sign)
}
#[inline]
pub(crate) fn atod(radix: u32, bytes: &[u8], sign: Sign)
-> (f64, usize)
{
to_native::<f64>(radix, bytes, false, sign)
}
#[inline]
pub(crate) fn atof_lossy(radix: u32, bytes: &[u8], sign: Sign)
-> (f32, usize)
{
to_native::<f32>(radix, bytes, true, sign)
}
#[inline]
pub(crate) fn atod_lossy(radix: u32, bytes: &[u8], sign: Sign)
-> (f64, usize)
{
to_native::<f64>(radix, bytes, true, sign)
}
#[cfg(test)]
mod tests {
use stackvector;
use lib::str;
use util::test::*;
use super::*;
#[test]
fn scientific_exponent_test() {
let slc = FloatSlice {
integer: "1".as_bytes(),
fraction: "2345".as_bytes(),
digits_start: 0,
digits_end: 4,
truncated: 0,
raw_exponent: 0,
};
assert_eq!(slc.scientific_exponent(), 0);
let slc = FloatSlice {
integer: "".as_bytes(),
fraction: "12345".as_bytes(),
digits_start: 0,
digits_end: 5,
truncated: 0,
raw_exponent: 0,
};
assert_eq!(slc.scientific_exponent(), -1);
}
fn check_parse_mantissa<M>(radix: u32, s: &str, tup: (M, usize, usize, usize, usize, &str))
where M: Mantissa
{
let (value, slc, bytes, _) = parse_mantissa::<M>(radix, s.as_bytes());
let digits: stackvector::StackVec<[u8; 1024]> = slc.mantissa_iter().cloned().collect();
let digits = str::from_utf8(&digits).unwrap();
assert_eq!(value, tup.0);
assert_eq!(slc.integer_len(), tup.1);
assert_eq!(slc.fraction_len(), tup.2);
assert_eq!(slc.truncated_digits(), tup.3);
assert_eq!(distance(s.as_ptr(), bytes.as_ptr()), tup.4);
assert_eq!(digits, tup.5);
}
#[test]
fn parse_mantissa_test() {
check_parse_mantissa::<u64>(10, "1.2345", (12345, 1, 4, 0, 6, "12345"));
check_parse_mantissa::<u64>(10, "12.345", (12345, 2, 3, 0, 6, "12345"));
check_parse_mantissa::<u64>(10, "12345.6789", (123456789, 5, 4, 0, 10, "123456789"));
check_parse_mantissa::<u64>(10, "1.2345e10", (12345, 1, 4, 0, 6, "12345"));
check_parse_mantissa::<u64>(10, "0.0000000000000000001", (1, 0, 19, 0, 21, "1"));
check_parse_mantissa::<u64>(10, "0.00000000000000000000000000001", (1, 0, 29, 0, 31, "1"));
check_parse_mantissa::<u64>(10, "100000000000000000000", (10000000000000000000, 21, 0, 1, 21, "100000000000000000000"));
check_parse_mantissa::<u64>(10, "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999", (17976931348623158079, 309, 70, 359, 380, "1797693134862315807937289714053034150799341327100378269361737789804449682927647509466490179775872070963302864166928879109465555478519404026306574886715058206819089020007083836762738548458177115317644757302700698555713669596228429148198608349364752927190741684443655107043427115596995080930428801779041744977919999999999999999999999999999999999999999999999999999999999999999999999"));
check_parse_mantissa::<u64>(10, "1009e-31", (1009, 4, 0, 0, 4, "1009"));
check_parse_mantissa::<u128>(10, "1.2345", (12345, 1, 4, 0, 6, "12345"));
check_parse_mantissa::<u128>(10, "12.345", (12345, 2, 3, 0, 6, "12345"));
check_parse_mantissa::<u128>(10, "12345.6789", (123456789, 5, 4, 0, 10, "123456789"));
check_parse_mantissa::<u128>(10, "1.2345e10", (12345, 1, 4, 0, 6, "12345"));
check_parse_mantissa::<u128>(10, "0.0000000000000000001", (1, 0, 19, 0, 21, "1"));
check_parse_mantissa::<u128>(10, "0.00000000000000000000000000001", (1, 0, 29, 0, 31, "1"));
check_parse_mantissa::<u128>(10, "100000000000000000000", (100000000000000000000, 21, 0, 0, 21, "100000000000000000000"));
}
fn check_parse_float<M>(radix: u32, s: &str, tup: (M, i32, i32, usize, usize, bool, &str))
where M: Mantissa
{
let (value, slc, bytes, truncated) = parse_float::<M>(radix, s.as_bytes());
let digits: stackvector::StackVec<[u8; 1024]> = slc.mantissa_iter().cloned().collect();
let digits = str::from_utf8(&digits).unwrap();
assert_eq!(value, tup.0);
assert_eq!(slc.mantissa_exponent(), tup.1);
assert_eq!(slc.scientific_exponent(), tup.2);
assert_eq!(slc.mantissa_digits(), tup.3);
assert_eq!(distance(s.as_ptr(), bytes.as_ptr()), tup.4);
assert_eq!(truncated.is_some(), tup.5);
assert_eq!(digits, tup.6);
assert_eq!(digits.len(), slc.mantissa_digits());
}
#[test]
fn parse_float_test() {
check_parse_float::<u64>(10, "1.2345", (12345, -4, 0, 5, 6, false, "12345"));
check_parse_float::<u64>(10, "12.345", (12345, -3, 1, 5, 6, false, "12345"));
check_parse_float::<u64>(10, "12345.6789", (123456789, -4, 4, 9, 10, false, "123456789"));
check_parse_float::<u64>(10, "1.2345e10", (12345, 6, 10, 5, 9, false, "12345"));
check_parse_float::<u64>(10, "100000000000000000000", (10000000000000000000, 1, 20, 21, 21, true, "100000000000000000000"));
check_parse_float::<u64>(10, "100000000000000000001", (10000000000000000000, 1, 20, 21, 21, true, "100000000000000000001"));
check_parse_float::<u64>(10, "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999", (17976931348623158079, 289, 308, 379, 380, true, "1797693134862315807937289714053034150799341327100378269361737789804449682927647509466490179775872070963302864166928879109465555478519404026306574886715058206819089020007083836762738548458177115317644757302700698555713669596228429148198608349364752927190741684443655107043427115596995080930428801779041744977919999999999999999999999999999999999999999999999999999999999999999999999"));
check_parse_float::<u64>(10, "1009e-31", (1009, -31, -28, 4, 8, false, "1009"));
check_parse_float::<u128>(10, "1.2345", (12345, -4, 0, 5, 6, false, "12345"));
check_parse_float::<u128>(10, "12.345", (12345, -3, 1, 5, 6, false, "12345"));
check_parse_float::<u128>(10, "12345.6789", (123456789, -4, 4, 9, 10, false, "123456789"));
check_parse_float::<u128>(10, "1.2345e10", (12345, 6, 10, 5, 9, false, "12345"));
check_parse_float::<u128>(10, "100000000000000000000", (100000000000000000000, 0, 20, 21, 21, false, "100000000000000000000"));
check_parse_float::<u128>(10, "100000000000000000001", (100000000000000000001, 0, 20, 21, 21, false, "100000000000000000001"));
}
#[cfg(feature = "radix")]
#[test]
fn is_odd_test() {
assert!(is_odd::<f32>(0x1000002));
assert!(is_odd::<f32>(0x2000004));
assert!(is_odd::<f32>(0x8000010000000000));
assert!(!is_odd::<f64>(0x1000002));
assert!(!is_odd::<f64>(0x2000004));
assert!(!is_odd::<f64>(0x8000010000000000));
assert!(!is_odd::<f32>(0x1000001));
assert!(!is_odd::<f32>(0x2000002));
assert!(!is_odd::<f32>(0x8000008000000000));
assert!(!is_odd::<f64>(0x1000001));
assert!(!is_odd::<f64>(0x2000002));
assert!(!is_odd::<f64>(0x8000008000000000));
assert!(!is_odd::<f32>(0x3f000000000002));
assert!(!is_odd::<f32>(0x3f000000000003));
assert!(!is_odd::<f32>(0xFC00000000000800));
assert!(!is_odd::<f32>(0xFC00000000000C00));
assert!(is_odd::<f64>(0x3f000000000002));
assert!(is_odd::<f64>(0x3f000000000003));
assert!(is_odd::<f64>(0xFC00000000000800));
assert!(is_odd::<f64>(0xFC00000000000C00));
assert!(!is_odd::<f32>(0x3f000000000001));
assert!(!is_odd::<f32>(0x3f000000000004));
assert!(!is_odd::<f32>(0xFC00000000000400));
assert!(!is_odd::<f32>(0xFC00000000001000));
assert!(!is_odd::<f64>(0x3f000000000001));
assert!(!is_odd::<f64>(0x3f000000000004));
assert!(!is_odd::<f64>(0xFC00000000000400));
assert!(!is_odd::<f64>(0xFC00000000001000));
}
#[cfg(feature = "radix")]
#[test]
fn is_halfway_test() {
assert!(is_halfway::<f32>(0x1000001));
assert!(is_halfway::<f32>(0x2000002));
assert!(is_halfway::<f32>(0x8000008000000000));
assert!(!is_halfway::<f64>(0x1000001));
assert!(!is_halfway::<f64>(0x2000002));
assert!(!is_halfway::<f64>(0x8000008000000000));
assert!(!is_halfway::<f32>(0x2000001));
assert!(!is_halfway::<f64>(0x2000001));
assert!(!is_halfway::<f32>(0x20000000000001));
assert!(!is_halfway::<f32>(0x40000000000002));
assert!(!is_halfway::<f32>(0x8000000000000400));
assert!(is_halfway::<f64>(0x20000000000001));
assert!(is_halfway::<f64>(0x40000000000002));
assert!(is_halfway::<f64>(0x8000000000000400));
assert!(!is_halfway::<f32>(0x3f000000000001));
assert!(!is_halfway::<f32>(0xFC00000000000400));
assert!(is_halfway::<f64>(0x3f000000000001));
assert!(is_halfway::<f64>(0xFC00000000000400));
assert!(!is_halfway::<f32>(0x40000000000001));
assert!(!is_halfway::<f64>(0x40000000000001));
}
#[cfg(feature = "radix")]
#[test]
fn float_pow2_fast_path() {
let mantissa = 1 << 63;
for base in BASE_POW2.iter().cloned() {
let (min_exp, max_exp) = f32::exponent_limit(base);
let pow2_exp = pow2_exponent(base);
for exp in min_exp-20..max_exp+30 {
pow2_fast_path::<f32>(mantissa, base, pow2_exp, exp);
}
}
}
#[cfg(feature = "radix")]
#[test]
fn double_pow2_fast_path_test() {
let mantissa = 1 << 63;
for base in BASE_POW2.iter().cloned() {
let (min_exp, max_exp) = f64::exponent_limit(base);
let pow2_exp = pow2_exponent(base);
for exp in min_exp-20..max_exp+30 {
pow2_fast_path::<f64>(mantissa, base, pow2_exp, exp);
}
}
}
#[test]
fn float_fast_path_test() {
let mantissa = (1 << f32::MANTISSA_SIZE) - 1;
for base in BASE_POWN.iter().cloned() {
let (min_exp, max_exp) = f32::exponent_limit(base);
for exp in min_exp..max_exp+1 {
let (_, valid) = fast_path::<f32>(mantissa, base, exp);
assert!(valid, "should be valid {:?}.", (mantissa, base, exp));
}
}
let (f, valid) = fast_path::<f32>(123, 10, 15);
assert_eq!(f, 1.23e+17);
assert!(valid);
let (_, valid) = fast_path::<f32>(123, 10, 16);
assert!(!valid);
let (_, valid) = fast_path::<f32>(mantissa, 10, 11);
assert!(!valid);
#[cfg(feature = "radix")] {
let (_, max_exp) = f64::exponent_limit(3);
let (_, valid) = fast_path::<f32>(1<<f32::MANTISSA_SIZE, 3, max_exp+1);
assert!(!valid, "invalid mantissa");
}
for base in BASE_POWN.iter().cloned() {
let (min_exp, max_exp) = f32::exponent_limit(base);
let (_, valid) = fast_path::<f32>(mantissa, base, min_exp-1);
assert!(!valid, "exponent under min_exp");
let (_, valid) = fast_path::<f32>(mantissa, base, max_exp+1);
assert!(!valid, "exponent above max_exp");
}
}
#[test]
fn double_fast_path_test() {
let mantissa = (1 << f64::MANTISSA_SIZE) - 1;
for base in BASE_POWN.iter().cloned() {
let (min_exp, max_exp) = f64::exponent_limit(base);
for exp in min_exp..max_exp+1 {
let (_, valid) = fast_path::<f64>(mantissa, base, exp);
assert!(valid, "should be valid {:?}.", (mantissa, base, exp));
}
}
#[cfg(feature = "radix")] {
let (_, max_exp) = f64::exponent_limit(3);
let (_, valid) = fast_path::<f64>(1<<f64::MANTISSA_SIZE, 3, max_exp+1);
assert!(!valid, "invalid mantissa");
}
for base in BASE_POWN.iter().cloned() {
let (min_exp, max_exp) = f64::exponent_limit(base);
let (_, valid) = fast_path::<f64>(mantissa, base, min_exp-1);
assert!(!valid, "exponent under min_exp");
let (_, valid) = fast_path::<f64>(mantissa, base, max_exp+1);
assert!(!valid, "exponent above max_exp");
}
}
#[cfg(feature = "radix")]
#[test]
fn float_moderate_path_test() {
let mantissa: u64 = 1 << 63;
let (f, valid) = moderate_path::<f32, _>(mantissa, 3, 1, false, RoundingKind::NearestTieEven);
assert_eq!(f.into_f32(), 2.7670116e+19);
assert!(valid, "exponent should be valid");
let mantissa: u64 = 4746067219335938;
let (f, valid) = moderate_path::<f32, _>(mantissa, 15, -9, false, RoundingKind::NearestTieEven);
assert_eq!(f.into_f32(), 123456.1);
assert!(valid, "exponent should be valid");
}
#[cfg(feature = "radix")]
#[test]
fn double_moderate_path_test() {
let mantissa: u64 = 1 << 63;
let (f, valid) = moderate_path::<f64, _>(mantissa, 3, 1, false, RoundingKind::NearestTieEven);
assert_eq!(f.into_f64(), 2.7670116110564327e+19);
assert!(valid, "exponent should be valid");
let (f, valid) = moderate_path::<f64, _>(mantissa, 3, -695, true, RoundingKind::NearestTieEven);
assert_eq!(f.into_f64(), 2.32069302345e-313);
assert!(valid, "exponent should be valid");
let mantissa: u64 = 4746067219335938;
let (_, valid) = moderate_path::<f64, _>(mantissa, 15, -9, false, RoundingKind::NearestTieEven);
assert!(!valid, "exponent should be invalid");
let mantissa: u128 = 4746067219335938;
let (f, valid) = moderate_path::<f64, _>(mantissa, 15, -9, false, RoundingKind::NearestTieEven);
assert_eq!(f.into_f64(), 123456.1);
assert!(valid, "exponent should be valid");
let mantissa: u64 = 1009;
let (_, valid) = moderate_path::<f64, _>(mantissa, 10, -31, false, RoundingKind::NearestTieEven);
assert!(!valid, "exponent should be valid");
}
fn check_atof(radix: u32, s: &str, tup: (f32, usize)) {
let (value, len) = atof(radix, s.as_bytes(), Sign::Positive);
assert_f32_eq!(value, tup.0);
assert_eq!(len, tup.1);
}
#[test]
fn atof_test() {
check_atof(10, "1.2345", (1.2345, 6));
check_atof(10, "12.345", (12.345, 6));
check_atof(10, "12345.6789", (12345.6789, 10));
check_atof(10, "1.2345e10", (1.2345e10, 9));
check_atof(10, "1.2345e-38", (1.2345e-38, 10));
check_atof(10, "16777216", (16777216.0, 8));
check_atof(10, "16777217", (16777216.0, 8));
check_atof(10, "16777218", (16777218.0, 8));
check_atof(10, "33554432", (33554432.0, 8));
check_atof(10, "33554434", (33554432.0, 8));
check_atof(10, "33554436", (33554436.0, 8));
check_atof(10, "17179869184", (17179869184.0, 11));
check_atof(10, "17179870208", (17179869184.0, 11));
check_atof(10, "17179871232", (17179871232.0, 11));
check_atof(10, "16777218", (16777218.0, 8));
check_atof(10, "16777219", (16777220.0, 8));
check_atof(10, "16777220", (16777220.0, 8));
check_atof(10, "33554436", (33554436.0, 8));
check_atof(10, "33554438", (33554440.0, 8));
check_atof(10, "33554440", (33554440.0, 8));
check_atof(10, "17179871232", (17179871232.0, 11));
check_atof(10, "17179872256", (17179873280.0, 11));
check_atof(10, "17179873280", (17179873280.0, 11));
check_atof(10, "33554435", (33554436.0, 8));
check_atof(10, "17179870209", (17179871232.0, 11));
check_atof(10, "1.00000017881393432617187499", (1.0000001, 28));
check_atof(10, "1.000000178813934326171875", (1.0000002, 26));
check_atof(10, "1.00000017881393432617187501", (1.0000002, 28));
}
fn check_atod(radix: u32, s: &str, tup: (f64, usize)) {
let (value, len) = atod(radix, s.as_bytes(), Sign::Positive);
assert_f64_eq!(value, tup.0);
assert_eq!(len, tup.1);
}
#[test]
fn atod_test() {
check_atod(10, "1.2345", (1.2345, 6));
check_atod(10, "12.345", (12.345, 6));
check_atod(10, "12345.6789", (12345.6789, 10));
check_atod(10, "1.2345e10", (1.2345e10, 9));
check_atod(10, "1.2345e-308", (1.2345e-308, 11));
check_atod(10, "9007199254740992", (9007199254740992.0, 16));
check_atod(10, "9007199254740993", (9007199254740992.0, 16));
check_atod(10, "9007199254740994", (9007199254740994.0, 16));
check_atod(10, "18014398509481984", (18014398509481984.0, 17));
check_atod(10, "18014398509481986", (18014398509481984.0, 17));
check_atod(10, "18014398509481988", (18014398509481988.0, 17));
check_atod(10, "9223372036854775808", (9223372036854775808.0, 19));
check_atod(10, "9223372036854776832", (9223372036854775808.0, 19));
check_atod(10, "9223372036854777856", (9223372036854777856.0, 19));
check_atod(10, "11417981541647679048466287755595961091061972992", (11417981541647679048466287755595961091061972992.0, 47));
check_atod(10, "11417981541647680316116887983825362587765178368", (11417981541647679048466287755595961091061972992.0, 47));
check_atod(10, "11417981541647681583767488212054764084468383744", (11417981541647681583767488212054764084468383744.0, 47));
check_atod(10, "9007199254740994", (9007199254740994.0, 16));
check_atod(10, "9007199254740995", (9007199254740996.0, 16));
check_atod(10, "9007199254740996", (9007199254740996.0, 16));
check_atod(10, "18014398509481988", (18014398509481988.0, 17));
check_atod(10, "18014398509481990", (18014398509481992.0, 17));
check_atod(10, "18014398509481992", (18014398509481992.0, 17));
check_atod(10, "9223372036854777856", (9223372036854777856.0, 19));
check_atod(10, "9223372036854778880", (9223372036854779904.0, 19));
check_atod(10, "9223372036854779904", (9223372036854779904.0, 19));
check_atod(10, "11417981541647681583767488212054764084468383744", (11417981541647681583767488212054764084468383744.0, 47));
check_atod(10, "11417981541647682851418088440284165581171589120", (11417981541647684119068688668513567077874794496.0, 47));
check_atod(10, "11417981541647684119068688668513567077874794496", (11417981541647684119068688668513567077874794496.0, 47));
check_atod(10, "9223372036854776833", (9223372036854777856.0, 19));
check_atod(10, "11417981541647680316116887983825362587765178369", (11417981541647681583767488212054764084468383744.0, 47));
check_atod(10, "2.2250738585072014e-308", (2.2250738585072014e-308, 23));
check_atod(10, "2.2250738585072011360574097967091319759348195463516456480234261097248222220210769455165295239081350879141491589130396211068700864386945946455276572074078206217433799881410632673292535522868813721490129811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306666559949382757725720157630626906633326475653000092458883164330377797918696120494973903778297049050510806099407302629371289589500035837999672072543043602840788957717961509455167482434710307026091446215722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844239002654981983854879482922068947216898310996983658468140228542433306603398508864458040010349339704275671864433837704860378616227717385456230658746790140867233276367187499e-308", (2.225073858507201e-308, 776));
check_atod(10, "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875e-308", (2.2250738585072014e-308, 774));
check_atod(10, "2.2250738585072011360574097967091319759348195463516456480234261097248222220210769455165295239081350879141491589130396211068700864386945946455276572074078206217433799881410632673292535522868813721490129811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306666559949382757725720157630626906633326475653000092458883164330377797918696120494973903778297049050510806099407302629371289589500035837999672072543043602840788957717961509455167482434710307026091446215722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844239002654981983854879482922068947216898310996983658468140228542433306603398508864458040010349339704275671864433837704860378616227717385456230658746790140867233276367187501e-308", (2.2250738585072014e-308, 776));
check_atod(10, "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999", (1.7976931348623157e+308, 380));
check_atod(10, "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999e-324", (5e-324, 761));
check_atod(10, "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375e-324", (1e-323, 758));
check_atod(10, "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001e-324", (1e-323, 761));
#[cfg(feature = "radix")]
check_atod(2, "1e-10000110010", (5e-324, 14));
#[cfg(feature = "radix")]
check_atod(2, "1e-10000110011", (0.0, 14));
check_atod(10, "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125", (0.0, 1077));
check_atod(10, "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375", (2.2250738585072011e-308, 1076));
check_atod(10, "1009e-31", (1.009e-28, 8));
check_atod(10, "18294e304", (f64::INFINITY, 9));
check_atod(10, "7.689539722041643e164", (7.689539722041643e164, 21));
check_atod(10, "768953972204164300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", (7.689539722041643e164, 165));
check_atod(10, "768953972204164300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", (7.689539722041643e164, 167));
check_atod(10, "9223372036854776833.0", (9223372036854777856.0, 21));
check_atod(10, "11417981541647680316116887983825362587765178369.0", (11417981541647681583767488212054764084468383744.0, 49));
check_atod(10, "9007199254740995.0", (9007199254740996.0, 18));
check_atod(10, "18014398509481990.0", (18014398509481992.0, 19));
check_atod(10, "9223372036854778880.0", (9223372036854779904.0, 21));
check_atod(10, "11417981541647682851418088440284165581171589120.0", (11417981541647684119068688668513567077874794496.0, 49));
}
fn check_atof_lossy(radix: u32, s: &str, tup: (f32, usize)) {
let (value, len) = atof_lossy(radix, s.as_bytes(), Sign::Positive);
assert_f32_eq!(value, tup.0);
assert_eq!(len, tup.1);
}
#[test]
fn atof_lossy_test() {
check_atof_lossy(10, "1.2345", (1.2345, 6));
check_atof_lossy(10, "12.345", (12.345, 6));
check_atof_lossy(10, "12345.6789", (12345.6789, 10));
check_atof_lossy(10, "1.2345e10", (1.2345e10, 9));
}
fn check_atod_lossy(radix: u32, s: &str, tup: (f64, usize)) {
let (value, len) = atod_lossy(radix, s.as_bytes(), Sign::Positive);
assert_f64_eq!(value, tup.0);
assert_eq!(len, tup.1);
}
#[test]
fn atod_lossy_test() {
check_atod_lossy(10, "1.2345", (1.2345, 6));
check_atod_lossy(10, "12.345", (12.345, 6));
check_atod_lossy(10, "12345.6789", (12345.6789, 10));
check_atod_lossy(10, "1.2345e10", (1.2345e10, 9));
}
}