//! 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 + Neg + Mul + Add + 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() } }