1//! Representation of a float as the significant digits and exponent.
23use super::float::RawFloat;
45#[rustfmt::skip]
6static INT_POW10: [u64; 16] = [
71,
810,
9100,
101000,
1110000,
12100000,
131000000,
1410000000,
15100000000,
161000000000,
1710000000000,
18100000000000,
191000000000000,
2010000000000000,
21100000000000000,
221000000000000000,
23];
2425#[derive(Clone, Copy, Default, PartialEq, Eq)]
26pub(crate) struct Number {
27pub(crate) exponent: i64,
28pub(crate) mantissa: u64,
29pub(crate) negative: bool,
30pub(crate) many_digits: bool,
31}
3233impl Number {
34/// Detect if the float can be accurately reconstructed from native floats.
35#[inline]
36fn is_fast_path<F: RawFloat>(&self) -> bool {
37 F::MIN_EXPONENT_FAST_PATH <= self.exponent
38 && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH
39 && self.mantissa <= F::MAX_MANTISSA_FAST_PATH
40 && !self.many_digits
41 }
4243/// The fast path algorithm using machine-sized integers and floats.
44 ///
45 /// This is extracted into a separate function so that it can be attempted before constructing
46 /// a Decimal. This only works if both the mantissa and the exponent
47 /// can be exactly represented as a machine float, since IEE-754 guarantees
48 /// no rounding will occur.
49 ///
50 /// There is an exception: disguised fast-path cases, where we can shift
51 /// powers-of-10 from the exponent to the significant digits.
52#[inline]
53pub(crate) fn try_fast_path<F: RawFloat>(&self) -> Option<F> {
54if self.is_fast_path::<F>() {
55let mut value = if self.exponent <= F::MAX_EXPONENT_FAST_PATH {
56// normal fast path
57let value = F::from_u64(self.mantissa);
58if self.exponent < 0 {
59 value / F::pow10_fast_path((-self.exponent) as usize)
60 } else {
61 value * F::pow10_fast_path(self.exponent as usize)
62 }
63 } else {
64// disguised fast path
65let shift = self.exponent - F::MAX_EXPONENT_FAST_PATH;
66let mantissa = self.mantissa.checked_mul(INT_POW10[shift as usize])?;
67if mantissa > F::MAX_MANTISSA_FAST_PATH {
68return None;
69 }
70 F::from_u64(mantissa) * F::pow10_fast_path(F::MAX_EXPONENT_FAST_PATH as usize)
71 };
72if self.negative {
73 value = -value;
74 }
75Some(value)
76 } else {
77None
78}
79 }
80}