mesh_loader/utils/float/
number.rs

1//! Representation of a float as the significant digits and exponent.
2
3use super::float::RawFloat;
4
5#[rustfmt::skip]
6static INT_POW10: [u64; 16] = [
7    1,
8    10,
9    100,
10    1000,
11    10000,
12    100000,
13    1000000,
14    10000000,
15    100000000,
16    1000000000,
17    10000000000,
18    100000000000,
19    1000000000000,
20    10000000000000,
21    100000000000000,
22    1000000000000000,
23];
24
25#[derive(Clone, Copy, Default, PartialEq, Eq)]
26pub(crate) struct Number {
27    pub(crate) exponent: i64,
28    pub(crate) mantissa: u64,
29    pub(crate) negative: bool,
30    pub(crate) many_digits: bool,
31}
32
33impl Number {
34    /// Detect if the float can be accurately reconstructed from native floats.
35    #[inline]
36    fn 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    }
42
43    /// 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]
53    pub(crate) fn try_fast_path<F: RawFloat>(&self) -> Option<F> {
54        if self.is_fast_path::<F>() {
55            let mut value = if self.exponent <= F::MAX_EXPONENT_FAST_PATH {
56                // normal fast path
57                let value = F::from_u64(self.mantissa);
58                if 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
65                let shift = self.exponent - F::MAX_EXPONENT_FAST_PATH;
66                let mantissa = self.mantissa.checked_mul(INT_POW10[shift as usize])?;
67                if mantissa > F::MAX_MANTISSA_FAST_PATH {
68                    return None;
69                }
70                F::from_u64(mantissa) * F::pow10_fast_path(F::MAX_EXPONENT_FAST_PATH as usize)
71            };
72            if self.negative {
73                value = -value;
74            }
75            Some(value)
76        } else {
77            None
78        }
79    }
80}