• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Adapted from https://github.com/Alexhuszagh/rust-lexical.
2 
3 //! Algorithms to efficiently convert strings to floats.
4 
5 use super::bhcomp::*;
6 use super::cached::*;
7 use super::errors::*;
8 use super::float::ExtendedFloat;
9 use super::num::*;
10 use super::small_powers::*;
11 
12 // FAST
13 // ----
14 
15 /// Convert mantissa to exact value for a non-base2 power.
16 ///
17 /// Returns the resulting float and if the value can be represented exactly.
fast_path<F>(mantissa: u64, exponent: i32) -> Option<F> where F: Float,18 pub(crate) fn fast_path<F>(mantissa: u64, exponent: i32) -> Option<F>
19 where
20     F: Float,
21 {
22     // `mantissa >> (F::MANTISSA_SIZE+1) != 0` effectively checks if the
23     // value has a no bits above the hidden bit, which is what we want.
24     let (min_exp, max_exp) = F::exponent_limit();
25     let shift_exp = F::mantissa_limit();
26     let mantissa_size = F::MANTISSA_SIZE + 1;
27     if mantissa == 0 {
28         Some(F::ZERO)
29     } else if mantissa >> mantissa_size != 0 {
30         // Would require truncation of the mantissa.
31         None
32     } else if exponent == 0 {
33         // 0 exponent, same as value, exact representation.
34         let float = F::as_cast(mantissa);
35         Some(float)
36     } else if exponent >= min_exp && exponent <= max_exp {
37         // Value can be exactly represented, return the value.
38         // Do not use powi, since powi can incrementally introduce
39         // error.
40         let float = F::as_cast(mantissa);
41         Some(float.pow10(exponent))
42     } else if exponent >= 0 && exponent <= max_exp + shift_exp {
43         // Check to see if we have a disguised fast-path, where the
44         // number of digits in the mantissa is very small, but and
45         // so digits can be shifted from the exponent to the mantissa.
46         // https://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
47         let small_powers = POW10_64;
48         let shift = exponent - max_exp;
49         let power = small_powers[shift as usize];
50 
51         // Compute the product of the power, if it overflows,
52         // prematurely return early, otherwise, if we didn't overshoot,
53         // we can get an exact value.
54         let value = mantissa.checked_mul(power)?;
55         if value >> mantissa_size != 0 {
56             None
57         } else {
58             // Use powi, since it's correct, and faster on
59             // the fast-path.
60             let float = F::as_cast(value);
61             Some(float.pow10(max_exp))
62         }
63     } else {
64         // Cannot be exactly represented, exponent too small or too big,
65         // would require truncation.
66         None
67     }
68 }
69 
70 // MODERATE
71 // --------
72 
73 /// Multiply the floating-point by the exponent.
74 ///
75 /// Multiply by pre-calculated powers of the base, modify the extended-
76 /// float, and return if new value and if the value can be represented
77 /// accurately.
multiply_exponent_extended<F>(fp: &mut ExtendedFloat, exponent: i32, truncated: bool) -> bool where F: Float,78 fn multiply_exponent_extended<F>(fp: &mut ExtendedFloat, exponent: i32, truncated: bool) -> bool
79 where
80     F: Float,
81 {
82     let powers = ExtendedFloat::get_powers();
83     let exponent = exponent.saturating_add(powers.bias);
84     let small_index = exponent % powers.step;
85     let large_index = exponent / powers.step;
86     if exponent < 0 {
87         // Guaranteed underflow (assign 0).
88         fp.mant = 0;
89         true
90     } else if large_index as usize >= powers.large.len() {
91         // Overflow (assign infinity)
92         fp.mant = 1 << 63;
93         fp.exp = 0x7FF;
94         true
95     } else {
96         // Within the valid exponent range, multiply by the large and small
97         // exponents and return the resulting value.
98 
99         // Track errors to as a factor of unit in last-precision.
100         let mut errors: u32 = 0;
101         if truncated {
102             errors += u64::error_halfscale();
103         }
104 
105         // Multiply by the small power.
106         // Check if we can directly multiply by an integer, if not,
107         // use extended-precision multiplication.
108         match fp
109             .mant
110             .overflowing_mul(powers.get_small_int(small_index as usize))
111         {
112             // Overflow, multiplication unsuccessful, go slow path.
113             (_, true) => {
114                 fp.normalize();
115                 fp.imul(&powers.get_small(small_index as usize));
116                 errors += u64::error_halfscale();
117             }
118             // No overflow, multiplication successful.
119             (mant, false) => {
120                 fp.mant = mant;
121                 fp.normalize();
122             }
123         }
124 
125         // Multiply by the large power
126         fp.imul(&powers.get_large(large_index as usize));
127         if errors > 0 {
128             errors += 1;
129         }
130         errors += u64::error_halfscale();
131 
132         // Normalize the floating point (and the errors).
133         let shift = fp.normalize();
134         errors <<= shift;
135 
136         u64::error_is_accurate::<F>(errors, &fp)
137     }
138 }
139 
140 /// Create a precise native float using an intermediate extended-precision float.
141 ///
142 /// Return the float approximation and if the value can be accurately
143 /// represented with mantissa bits of precision.
144 #[inline]
moderate_path<F>( mantissa: u64, exponent: i32, truncated: bool, ) -> (ExtendedFloat, bool) where F: Float,145 pub(crate) fn moderate_path<F>(
146     mantissa: u64,
147     exponent: i32,
148     truncated: bool,
149 ) -> (ExtendedFloat, bool)
150 where
151     F: Float,
152 {
153     let mut fp = ExtendedFloat {
154         mant: mantissa,
155         exp: 0,
156     };
157     let valid = multiply_exponent_extended::<F>(&mut fp, exponent, truncated);
158     (fp, valid)
159 }
160 
161 // FALLBACK
162 // --------
163 
164 /// Fallback path when the fast path does not work.
165 ///
166 /// Uses the moderate path, if applicable, otherwise, uses the slow path
167 /// as required.
fallback_path<F>( integer: &[u8], fraction: &[u8], mantissa: u64, exponent: i32, mantissa_exponent: i32, truncated: bool, ) -> F where F: Float,168 pub(crate) fn fallback_path<F>(
169     integer: &[u8],
170     fraction: &[u8],
171     mantissa: u64,
172     exponent: i32,
173     mantissa_exponent: i32,
174     truncated: bool,
175 ) -> F
176 where
177     F: Float,
178 {
179     // Moderate path (use an extended 80-bit representation).
180     let (fp, valid) = moderate_path::<F>(mantissa, mantissa_exponent, truncated);
181     if valid {
182         return fp.into_float::<F>();
183     }
184 
185     // Slow path, fast path didn't work.
186     let b = fp.into_downward_float::<F>();
187     if b.is_special() {
188         // We have a non-finite number, we get to leave early.
189         b
190     } else {
191         bhcomp(b, integer, fraction, exponent)
192     }
193 }
194