• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Representation of a float as the significant digits and exponent.
2 //!
3 //! This is adapted from [fast-float-rust](https://github.com/aldanor/fast-float-rust),
4 //! a port of [fast_float](https://github.com/fastfloat/fast_float) to Rust.
5 
6 #![doc(hidden)]
7 
8 #[cfg(feature = "nightly")]
9 use crate::fpu::set_precision;
10 use crate::num::Float;
11 
12 /// Representation of a number as the significant digits and exponent.
13 ///
14 /// This is only used if the exponent base and the significant digit
15 /// radix are the same, since we need to be able to move powers in and
16 /// out of the exponent.
17 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
18 pub struct Number {
19     /// The exponent of the float, scaled to the mantissa.
20     pub exponent: i32,
21     /// The significant digits of the float.
22     pub mantissa: u64,
23     /// If the significant digits were truncated.
24     pub many_digits: bool,
25 }
26 
27 impl Number {
28     /// Detect if the float can be accurately reconstructed from native floats.
29     #[inline]
is_fast_path<F: Float>(&self) -> bool30     pub fn is_fast_path<F: Float>(&self) -> bool {
31         F::MIN_EXPONENT_FAST_PATH <= self.exponent
32             && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH
33             && self.mantissa <= F::MAX_MANTISSA_FAST_PATH
34             && !self.many_digits
35     }
36 
37     /// The fast path algorithmn using machine-sized integers and floats.
38     ///
39     /// This is extracted into a separate function so that it can be attempted before constructing
40     /// a Decimal. This only works if both the mantissa and the exponent
41     /// can be exactly represented as a machine float, since IEE-754 guarantees
42     /// no rounding will occur.
43     ///
44     /// There is an exception: disguised fast-path cases, where we can shift
45     /// powers-of-10 from the exponent to the significant digits.
try_fast_path<F: Float>(&self) -> Option<F>46     pub fn try_fast_path<F: Float>(&self) -> Option<F> {
47         // The fast path crucially depends on arithmetic being rounded to the correct number of bits
48         // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision
49         // of the x87 FPU stack to be changed so that it directly rounds to 64/32 bit.
50         // The `set_precision` function takes care of setting the precision on architectures which
51         // require setting it by changing the global state (like the control word of the x87 FPU).
52         #[cfg(feature = "nightly")]
53         let _cw = set_precision::<F>();
54 
55         if self.is_fast_path::<F>() {
56             let max_exponent = F::MAX_EXPONENT_FAST_PATH;
57             Some(if self.exponent <= max_exponent {
58                 // normal fast path
59                 let value = F::from_u64(self.mantissa);
60                 if self.exponent < 0 {
61                     // SAFETY: safe, since the `exponent <= max_exponent`.
62                     value / unsafe { F::pow_fast_path((-self.exponent) as _) }
63                 } else {
64                     // SAFETY: safe, since the `exponent <= max_exponent`.
65                     value * unsafe { F::pow_fast_path(self.exponent as _) }
66                 }
67             } else {
68                 // disguised fast path
69                 let shift = self.exponent - max_exponent;
70                 // SAFETY: safe, since `shift <= (max_disguised - max_exponent)`.
71                 let int_power = unsafe { F::int_pow_fast_path(shift as usize, 10) };
72                 let mantissa = self.mantissa.checked_mul(int_power)?;
73                 if mantissa > F::MAX_MANTISSA_FAST_PATH {
74                     return None;
75                 }
76                 // SAFETY: safe, since the `table.len() - 1 == max_exponent`.
77                 F::from_u64(mantissa) * unsafe { F::pow_fast_path(max_exponent as _) }
78             })
79         } else {
80             None
81         }
82     }
83 }
84