use super::bhcomp::*;
use super::cached::*;
use super::errors::*;
use super::float::ExtendedFloat;
use super::num::*;
use super::small_powers::*;
pub(crate) fn fast_path<F>(mantissa: u64, exponent: i32)
-> Option<F>
where F: Float
{
let (min_exp, max_exp) = F::exponent_limit();
let shift_exp = F::mantissa_limit();
let mantissa_size = F::MANTISSA_SIZE + 1;
if mantissa >> mantissa_size != 0 {
None
} else if exponent == 0 {
let float = F::as_cast(mantissa);
Some(float)
} else if exponent >= min_exp && exponent <= max_exp {
let float = F::as_cast(mantissa);
Some(float.pow10(exponent))
} else if exponent >= 0 && exponent <= max_exp + shift_exp {
let small_powers = POW10_64;
let shift = exponent - max_exp;
let power = small_powers[shift.as_usize()];
let value = mantissa.checked_mul(power)?;
if value >> mantissa_size != 0 {
None
} else {
let float = F::as_cast(value);
Some(float.pow10(max_exp))
}
} else {
None
}
}
fn multiply_exponent_extended<F>(fp: &mut ExtendedFloat, exponent: i32, truncated: bool)
-> bool
where F: Float
{
let powers = ExtendedFloat::get_powers();
let exponent = exponent.saturating_add(powers.bias);
let small_index = exponent % powers.step;
let large_index = exponent / powers.step;
if exponent < 0 {
fp.mant = 0;
true
} else if large_index as usize >= powers.large.len() {
fp.mant = 1 << 63;
fp.exp = 0x7FF;
true
} else {
let mut errors: u32 = 0;
if truncated {
errors += u64::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 += u64::error_halfscale();
},
(mant, false) => {
fp.mant = mant;
fp.normalize();
},
}
fp.imul(&powers.get_large(large_index.as_usize()));
if errors > 0 {
errors += 1;
}
errors += u64::error_halfscale();
let shift = fp.normalize();
errors <<= shift;
u64::error_is_accurate::<F>(errors, &fp)
}
}
#[inline]
fn moderate_path<F>(mantissa: u64, exponent: i32, truncated: bool) -> (ExtendedFloat, bool)
where F: Float
{
let mut fp = ExtendedFloat { mant: mantissa, exp: 0 };
let valid = multiply_exponent_extended::<F>(&mut fp, exponent, truncated);
(fp, valid)
}
pub(crate) fn fallback_path<'a, F, Iter1, Iter2>(
integer: Iter1,
fraction: Iter2,
mantissa: u64,
exponent: i32,
mantissa_exponent: i32,
truncated: bool
) -> F
where F: Float,
Iter1: Iterator<Item=&'a u8> + Clone,
Iter2: Iterator<Item=&'a u8> + Clone
{
let (fp, valid) = moderate_path::<F>(mantissa, mantissa_exponent, truncated);
if valid {
return fp.into_float::<F>();
}
let b = fp.into_downward_float::<F>();
if b.is_special() {
return b;
} else {
return bhcomp(b, integer, fraction, exponent);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn float_fast_path_test() {
let mantissa = (1 << f32::MANTISSA_SIZE) - 1;
let (min_exp, max_exp) = f32::exponent_limit();
for exp in min_exp..max_exp+1 {
let f = fast_path::<f32>(mantissa, exp);
assert!(f.is_some(), "should be valid {:?}.", (mantissa, exp));
}
let f = fast_path::<f32>(123, 15);
assert_eq!(f, Some(1.23e+17));
let f = fast_path::<f32>(123, 16);
assert!(f.is_none());
let f = fast_path::<f32>(mantissa, 11);
assert!(f.is_none());
#[cfg(feature = "radix")] {
let (_, max_exp) = f64::exponent_limit(3);
let f = fast_path::<f32>(1<<f32::MANTISSA_SIZE, 3, max_exp+1);
assert!(f.is_none(), "invalid mantissa");
}
let (min_exp, max_exp) = f32::exponent_limit();
let f = fast_path::<f32>(mantissa, min_exp-1);
assert!(f.is_none(), "exponent under min_exp");
let f = fast_path::<f32>(mantissa, max_exp+1);
assert!(f.is_none(), "exponent above max_exp");
}
#[test]
fn double_fast_path_test() {
let mantissa = (1 << f64::MANTISSA_SIZE) - 1;
let (min_exp, max_exp) = f64::exponent_limit();
for exp in min_exp..max_exp+1 {
let f = fast_path::<f64>(mantissa, exp);
assert!(f.is_some(), "should be valid {:?}.", (mantissa, exp));
}
#[cfg(feature = "radix")] {
let (_, max_exp) = f64::exponent_limit(3);
let f = fast_path::<f64>(1<<f64::MANTISSA_SIZE, 3, max_exp+1);
assert!(f.is_none(), "invalid mantissa");
}
let (min_exp, max_exp) = f64::exponent_limit();
let f = fast_path::<f64>(mantissa, min_exp-1);
assert!(f.is_none(), "exponent under min_exp");
let f = fast_path::<f64>(mantissa, max_exp+1);
assert!(f.is_none(), "exponent above max_exp");
assert_eq!(Some(0.04628372940652459), fast_path::<f64>(4628372940652459, -17));
assert_eq!(None, fast_path::<f64>(26383446160308229, -272));
}
#[test]
fn moderate_path_test() {
let (f, valid) = moderate_path::<f64>(1234567890, -1, false);
assert!(valid, "should be valid");
assert_eq!(f.into_float::<f64>(), 123456789.0);
let (f, valid) = moderate_path::<f64>(1234567891, -1, false);
assert!(valid, "should be valid");
assert_eq!(f.into_float::<f64>(), 123456789.1);
let (f, valid) = moderate_path::<f64>(12345678912, -2, false);
assert!(valid, "should be valid");
assert_eq!(f.into_float::<f64>(), 123456789.12);
let (f, valid) = moderate_path::<f64>(123456789123, -3, false);
assert!(valid, "should be valid");
assert_eq!(f.into_float::<f64>(), 123456789.123);
let (f, valid) = moderate_path::<f64>(1234567891234, -4, false);
assert!(valid, "should be valid");
assert_eq!(f.into_float::<f64>(), 123456789.1234);
let (f, valid) = moderate_path::<f64>(12345678912345, -5, false);
assert!(valid, "should be valid");
assert_eq!(f.into_float::<f64>(), 123456789.12345);
let (f, valid) = moderate_path::<f64>(123456789123456, -6, false);
assert!(valid, "should be valid");
assert_eq!(f.into_float::<f64>(), 123456789.123456);
let (f, valid) = moderate_path::<f64>(1234567891234567, -7, false);
assert!(valid, "should be valid");
assert_eq!(f.into_float::<f64>(), 123456789.1234567);
let (f, valid) = moderate_path::<f64>(12345678912345679, -8, false);
assert!(valid, "should be valid");
assert_eq!(f.into_float::<f64>(), 123456789.12345679);
let (f, valid) = moderate_path::<f64>(4628372940652459, -17, false);
assert!(valid, "should be valid");
assert_eq!(f.into_float::<f64>(), 0.04628372940652459);
let (f, valid) = moderate_path::<f64>(26383446160308229, -272, false);
assert!(valid, "should be valid");
assert_eq!(f.into_float::<f64>(), 2.6383446160308229e-256);
let (_, valid) = moderate_path::<f64>(26383446160308230, -272, false);
assert!(!valid, "should be invalid");
}
#[test]
fn fallback_path_test() {
}
}