summaryrefslogtreecommitdiffstats
path: root/third_party/rust/minimal-lexical/src/number.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/minimal-lexical/src/number.rs')
-rw-r--r--third_party/rust/minimal-lexical/src/number.rs83
1 files changed, 83 insertions, 0 deletions
diff --git a/third_party/rust/minimal-lexical/src/number.rs b/third_party/rust/minimal-lexical/src/number.rs
new file mode 100644
index 0000000000..5981f9dd79
--- /dev/null
+++ b/third_party/rust/minimal-lexical/src/number.rs
@@ -0,0 +1,83 @@
+//! Representation of a float as the significant digits and exponent.
+//!
+//! This is adapted from [fast-float-rust](https://github.com/aldanor/fast-float-rust),
+//! a port of [fast_float](https://github.com/fastfloat/fast_float) to Rust.
+
+#![doc(hidden)]
+
+#[cfg(feature = "nightly")]
+use crate::fpu::set_precision;
+use crate::num::Float;
+
+/// Representation of a number as the significant digits and exponent.
+///
+/// This is only used if the exponent base and the significant digit
+/// radix are the same, since we need to be able to move powers in and
+/// out of the exponent.
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
+pub struct Number {
+ /// The exponent of the float, scaled to the mantissa.
+ pub exponent: i32,
+ /// The significant digits of the float.
+ pub mantissa: u64,
+ /// If the significant digits were truncated.
+ pub many_digits: bool,
+}
+
+impl Number {
+ /// Detect if the float can be accurately reconstructed from native floats.
+ #[inline]
+ pub fn is_fast_path<F: Float>(&self) -> bool {
+ F::MIN_EXPONENT_FAST_PATH <= self.exponent
+ && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH
+ && self.mantissa <= F::MAX_MANTISSA_FAST_PATH
+ && !self.many_digits
+ }
+
+ /// The fast path algorithmn using machine-sized integers and floats.
+ ///
+ /// This is extracted into a separate function so that it can be attempted before constructing
+ /// a Decimal. This only works if both the mantissa and the exponent
+ /// can be exactly represented as a machine float, since IEE-754 guarantees
+ /// no rounding will occur.
+ ///
+ /// There is an exception: disguised fast-path cases, where we can shift
+ /// powers-of-10 from the exponent to the significant digits.
+ pub fn try_fast_path<F: Float>(&self) -> Option<F> {
+ // The fast path crucially depends on arithmetic being rounded to the correct number of bits
+ // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision
+ // of the x87 FPU stack to be changed so that it directly rounds to 64/32 bit.
+ // The `set_precision` function takes care of setting the precision on architectures which
+ // require setting it by changing the global state (like the control word of the x87 FPU).
+ #[cfg(feature = "nightly")]
+ let _cw = set_precision::<F>();
+
+ if self.is_fast_path::<F>() {
+ let max_exponent = F::MAX_EXPONENT_FAST_PATH;
+ Some(if self.exponent <= max_exponent {
+ // normal fast path
+ let value = F::from_u64(self.mantissa);
+ if self.exponent < 0 {
+ // SAFETY: safe, since the `exponent <= max_exponent`.
+ value / unsafe { F::pow_fast_path((-self.exponent) as _) }
+ } else {
+ // SAFETY: safe, since the `exponent <= max_exponent`.
+ value * unsafe { F::pow_fast_path(self.exponent as _) }
+ }
+ } else {
+ // disguised fast path
+ let shift = self.exponent - max_exponent;
+ // SAFETY: safe, since `shift <= (max_disguised - max_exponent)`.
+ let int_power = unsafe { F::int_pow_fast_path(shift as usize, 10) };
+ let mantissa = self.mantissa.checked_mul(int_power)?;
+ if mantissa > F::MAX_MANTISSA_FAST_PATH {
+ return None;
+ }
+ // SAFETY: safe, since the `table.len() - 1 == max_exponent`.
+ F::from_u64(mantissa) * unsafe { F::pow_fast_path(max_exponent as _) }
+ })
+ } else {
+ None
+ }
+ }
+}