1//! Representation of a float as the significant digits and exponent.
23use dec2flt::Lemire;
4use dec2flt::fpu::set_precision;
56use crate::num::imp::dec2flt;
78const INT_POW10: [u64; 16] = [
91,
1010,
11100,
121000,
1310000,
14100000,
151000000,
1610000000,
17100000000,
181000000000,
1910000000000,
20100000000000,
211000000000000,
2210000000000000,
23100000000000000,
241000000000000000,
25];
2627/// A floating point number with up to 64 bits of mantissa and an `i64` exponent.
28#[derive(#[automatically_derived]
impl crate::clone::Clone for Decimal {
#[inline]
fn clone(&self) -> Decimal {
let _: crate::clone::AssertParamIsClone<i64>;
let _: crate::clone::AssertParamIsClone<u64>;
let _: crate::clone::AssertParamIsClone<bool>;
*self
}
}Clone, #[automatically_derived]
impl crate::marker::Copy for Decimal { }Copy, #[automatically_derived]
impl crate::fmt::Debug for Decimal {
#[inline]
fn fmt(&self, f: &mut crate::fmt::Formatter) -> crate::fmt::Result {
crate::fmt::Formatter::debug_struct_field4_finish(f, "Decimal",
"exponent", &self.exponent, "mantissa", &self.mantissa,
"negative", &self.negative, "many_digits", &&self.many_digits)
}
}Debug, #[automatically_derived]
impl crate::default::Default for Decimal {
#[inline]
fn default() -> Decimal {
Decimal {
exponent: crate::default::Default::default(),
mantissa: crate::default::Default::default(),
negative: crate::default::Default::default(),
many_digits: crate::default::Default::default(),
}
}
}Default, #[automatically_derived]
impl crate::cmp::PartialEq for Decimal {
#[inline]
fn eq(&self, other: &Decimal) -> bool {
self.exponent == other.exponent && self.mantissa == other.mantissa &&
self.negative == other.negative &&
self.many_digits == other.many_digits
}
}PartialEq, #[automatically_derived]
impl crate::cmp::Eq for Decimal {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: crate::cmp::AssertParamIsEq<i64>;
let _: crate::cmp::AssertParamIsEq<u64>;
let _: crate::cmp::AssertParamIsEq<bool>;
}
}Eq)]
29pub struct Decimal {
30pub exponent: i64,
31pub mantissa: u64,
32pub negative: bool,
33pub many_digits: bool,
34}
3536impl Decimal {
37/// Detect if the float can be accurately reconstructed from native floats.
38#[inline]
39fn can_use_fast_path<F: Lemire>(&self) -> bool {
40 F::MIN_EXPONENT_FAST_PATH <= self.exponent
41 && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH42 && self.mantissa <= F::MAX_MANTISSA_FAST_PATH43 && !self.many_digits
44 }
4546/// Try turning the decimal into an exact float representation, using machine-sized integers
47 /// and floats.
48 ///
49 /// This is extracted into a separate function so that it can be attempted before constructing
50 /// a Decimal. This only works if both the mantissa and the exponent
51 /// can be exactly represented as a machine float, since IEE-754 guarantees
52 /// no rounding will occur.
53 ///
54 /// There is an exception: disguised fast-path cases, where we can shift
55 /// powers-of-10 from the exponent to the significant digits.
56pub fn try_fast_path<F: Lemire>(&self) -> Option<F> {
57// Here we need to work around <https://github.com/rust-lang/rust/issues/114479>.
58 // The fast path crucially depends on arithmetic being rounded to the correct number of bits
59 // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision
60 // of the x87 FPU stack to be changed so that it directly rounds to 64/32 bit.
61 // The `set_precision` function takes care of setting the precision on architectures which
62 // require setting it by changing the global state (like the control word of the x87 FPU).
63let _cw = set_precision::<F>();
6465if !self.can_use_fast_path::<F>() {
66return None;
67 }
6869let value = if self.exponent <= F::MAX_EXPONENT_FAST_PATH {
70// normal fast path
71let value = F::from_u64(self.mantissa);
72if self.exponent < 0 {
73value / F::pow10_fast_path((-self.exponent) as _)
74 } else {
75value * F::pow10_fast_path(self.exponent as _)
76 }
77 } else {
78// disguised fast path
79let shift = self.exponent - F::MAX_EXPONENT_FAST_PATH;
80let mantissa = self.mantissa.checked_mul(INT_POW10[shiftas usize])?;
81if mantissa > F::MAX_MANTISSA_FAST_PATH {
82return None;
83 }
84 F::from_u64(mantissa) * F::pow10_fast_path(F::MAX_EXPONENT_FAST_PATHas _)
85 };
8687if self.negative { Some(-value) } else { Some(value) }
88 }
89}