summaryrefslogtreecommitdiffstats
path: root/library/core/src/num/dec2flt/float.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/core/src/num/dec2flt/float.rs')
-rw-r--r--library/core/src/num/dec2flt/float.rs207
1 files changed, 207 insertions, 0 deletions
diff --git a/library/core/src/num/dec2flt/float.rs b/library/core/src/num/dec2flt/float.rs
new file mode 100644
index 000000000..5921c5ed4
--- /dev/null
+++ b/library/core/src/num/dec2flt/float.rs
@@ -0,0 +1,207 @@
+//! Helper trait for generic float types.
+
+use crate::fmt::{Debug, LowerExp};
+use crate::num::FpCategory;
+use crate::ops::{Add, Div, Mul, Neg};
+
+/// A helper trait to avoid duplicating basically all the conversion code for `f32` and `f64`.
+///
+/// See the parent module's doc comment for why this is necessary.
+///
+/// Should **never ever** be implemented for other types or be used outside the dec2flt module.
+#[doc(hidden)]
+pub trait RawFloat:
+ Sized
+ + Div<Output = Self>
+ + Neg<Output = Self>
+ + Mul<Output = Self>
+ + Add<Output = Self>
+ + LowerExp
+ + PartialEq
+ + PartialOrd
+ + Default
+ + Clone
+ + Copy
+ + Debug
+{
+ const INFINITY: Self;
+ const NEG_INFINITY: Self;
+ const NAN: Self;
+ const NEG_NAN: Self;
+
+ /// The number of bits in the significand, *excluding* the hidden bit.
+ const MANTISSA_EXPLICIT_BITS: usize;
+
+ // Round-to-even only happens for negative values of q
+ // when q ≥ −4 in the 64-bit case and when q ≥ −17 in
+ // the 32-bitcase.
+ //
+ // When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we
+ // have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have
+ // 5^q ≤ 2m+1 ≤ 2^25 or q ≤ 10.
+ //
+ // When q < 0, we have w ≥ (2m+1)×5^−q. We must have that w < 2^64
+ // so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case)
+ // or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64
+ // (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11
+ // or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bitcase).
+ //
+ // Thus we have that we only need to round ties to even when
+ // we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10]
+ // (in the 32-bit case). In both cases,the power of five(5^|q|)
+ // fits in a 64-bit word.
+ const MIN_EXPONENT_ROUND_TO_EVEN: i32;
+ const MAX_EXPONENT_ROUND_TO_EVEN: i32;
+
+ // Minimum exponent that for a fast path case, or `-⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋`
+ const MIN_EXPONENT_FAST_PATH: i64;
+
+ // Maximum exponent that for a fast path case, or `⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋`
+ const MAX_EXPONENT_FAST_PATH: i64;
+
+ // Maximum exponent that can be represented for a disguised-fast path case.
+ // This is `MAX_EXPONENT_FAST_PATH + ⌊(MANTISSA_EXPLICIT_BITS+1)/log2(10)⌋`
+ const MAX_EXPONENT_DISGUISED_FAST_PATH: i64;
+
+ // Minimum exponent value `-(1 << (EXP_BITS - 1)) + 1`.
+ const MINIMUM_EXPONENT: i32;
+
+ // Largest exponent value `(1 << EXP_BITS) - 1`.
+ const INFINITE_POWER: i32;
+
+ // Index (in bits) of the sign.
+ const SIGN_INDEX: usize;
+
+ // Smallest decimal exponent for a non-zero value.
+ const SMALLEST_POWER_OF_TEN: i32;
+
+ // Largest decimal exponent for a non-infinite value.
+ const LARGEST_POWER_OF_TEN: i32;
+
+ // Maximum mantissa for the fast-path (`1 << 53` for f64).
+ const MAX_MANTISSA_FAST_PATH: u64 = 2_u64 << Self::MANTISSA_EXPLICIT_BITS;
+
+ /// Convert integer into float through an as cast.
+ /// This is only called in the fast-path algorithm, and therefore
+ /// will not lose precision, since the value will always have
+ /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH.
+ fn from_u64(v: u64) -> Self;
+
+ /// Performs a raw transmutation from an integer.
+ fn from_u64_bits(v: u64) -> Self;
+
+ /// Get a small power-of-ten for fast-path multiplication.
+ fn pow10_fast_path(exponent: usize) -> Self;
+
+ /// Returns the category that this number falls into.
+ fn classify(self) -> FpCategory;
+
+ /// Returns the mantissa, exponent and sign as integers.
+ fn integer_decode(self) -> (u64, i16, i8);
+}
+
+impl RawFloat for f32 {
+ const INFINITY: Self = f32::INFINITY;
+ const NEG_INFINITY: Self = f32::NEG_INFINITY;
+ const NAN: Self = f32::NAN;
+ const NEG_NAN: Self = -f32::NAN;
+
+ const MANTISSA_EXPLICIT_BITS: usize = 23;
+ const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17;
+ const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
+ const MIN_EXPONENT_FAST_PATH: i64 = -10; // assuming FLT_EVAL_METHOD = 0
+ const MAX_EXPONENT_FAST_PATH: i64 = 10;
+ const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 17;
+ const MINIMUM_EXPONENT: i32 = -127;
+ const INFINITE_POWER: i32 = 0xFF;
+ const SIGN_INDEX: usize = 31;
+ const SMALLEST_POWER_OF_TEN: i32 = -65;
+ const LARGEST_POWER_OF_TEN: i32 = 38;
+
+ fn from_u64(v: u64) -> Self {
+ debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
+ v as _
+ }
+
+ fn from_u64_bits(v: u64) -> Self {
+ f32::from_bits((v & 0xFFFFFFFF) as u32)
+ }
+
+ fn pow10_fast_path(exponent: usize) -> Self {
+ #[allow(clippy::use_self)]
+ const TABLE: [f32; 16] =
+ [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.];
+ TABLE[exponent & 15]
+ }
+
+ /// Returns the mantissa, exponent and sign as integers.
+ fn integer_decode(self) -> (u64, i16, i8) {
+ let bits = self.to_bits();
+ let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
+ let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
+ let mantissa =
+ if exponent == 0 { (bits & 0x7fffff) << 1 } else { (bits & 0x7fffff) | 0x800000 };
+ // Exponent bias + mantissa shift
+ exponent -= 127 + 23;
+ (mantissa as u64, exponent, sign)
+ }
+
+ fn classify(self) -> FpCategory {
+ self.classify()
+ }
+}
+
+impl RawFloat for f64 {
+ const INFINITY: Self = f64::INFINITY;
+ const NEG_INFINITY: Self = f64::NEG_INFINITY;
+ const NAN: Self = f64::NAN;
+ const NEG_NAN: Self = -f64::NAN;
+
+ const MANTISSA_EXPLICIT_BITS: usize = 52;
+ const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -4;
+ const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23;
+ const MIN_EXPONENT_FAST_PATH: i64 = -22; // assuming FLT_EVAL_METHOD = 0
+ const MAX_EXPONENT_FAST_PATH: i64 = 22;
+ const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 37;
+ const MINIMUM_EXPONENT: i32 = -1023;
+ const INFINITE_POWER: i32 = 0x7FF;
+ const SIGN_INDEX: usize = 63;
+ const SMALLEST_POWER_OF_TEN: i32 = -342;
+ const LARGEST_POWER_OF_TEN: i32 = 308;
+
+ fn from_u64(v: u64) -> Self {
+ debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
+ v as _
+ }
+
+ fn from_u64_bits(v: u64) -> Self {
+ f64::from_bits(v)
+ }
+
+ fn pow10_fast_path(exponent: usize) -> Self {
+ const TABLE: [f64; 32] = [
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
+ 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0.,
+ ];
+ TABLE[exponent & 31]
+ }
+
+ /// Returns the mantissa, exponent and sign as integers.
+ fn integer_decode(self) -> (u64, i16, i8) {
+ let bits = self.to_bits();
+ let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
+ let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
+ let mantissa = if exponent == 0 {
+ (bits & 0xfffffffffffff) << 1
+ } else {
+ (bits & 0xfffffffffffff) | 0x10000000000000
+ };
+ // Exponent bias + mantissa shift
+ exponent -= 1023 + 52;
+ (mantissa, exponent, sign)
+ }
+
+ fn classify(self) -> FpCategory {
+ self.classify()
+ }
+}