mesh_loader/utils/float/
float.rs

1//! Helper trait for generic float types.
2
3use core::ops::{Div, Mul, Neg};
4
5/// A helper trait to avoid duplicating basically all the conversion code for `f32` and `f64`.
6pub trait RawFloat: Copy + Div<Output = Self> + Neg<Output = Self> + Mul<Output = Self> {
7    const INFINITY: Self;
8    const NEG_INFINITY: Self;
9    const NAN: Self;
10    const NEG_NAN: Self;
11
12    /// The number of bits in the significand, *excluding* the hidden bit.
13    const MANTISSA_EXPLICIT_BITS: usize;
14
15    // Round-to-even only happens for negative values of q
16    // when q ≥ −4 in the 64-bit case and when q ≥ −17 in
17    // the 32-bit case.
18    //
19    // When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we
20    // have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have
21    // 5^q ≤ 2m+1 ≤ 2^25 or q ≤ 10.
22    //
23    // When q < 0, we have w ≥ (2m+1)×5^−q. We must have that w < 2^64
24    // so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case)
25    // or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64
26    // (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11
27    // or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bit case).
28    //
29    // Thus we have that we only need to round ties to even when
30    // we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10]
31    // (in the 32-bit case). In both cases,the power of five(5^|q|)
32    // fits in a 64-bit word.
33    const MIN_EXPONENT_ROUND_TO_EVEN: i32;
34    const MAX_EXPONENT_ROUND_TO_EVEN: i32;
35
36    // Minimum exponent that for a fast path case, or `-⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋`
37    const MIN_EXPONENT_FAST_PATH: i64;
38
39    // Maximum exponent that for a fast path case, or `⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋`
40    const MAX_EXPONENT_FAST_PATH: i64;
41
42    // Maximum exponent that can be represented for a disguised-fast path case.
43    // This is `MAX_EXPONENT_FAST_PATH + ⌊(MANTISSA_EXPLICIT_BITS+1)/log2(10)⌋`
44    const MAX_EXPONENT_DISGUISED_FAST_PATH: i64;
45
46    // Minimum exponent value `-(1 << (EXP_BITS - 1)) + 1`.
47    const MINIMUM_EXPONENT: i32;
48
49    // Largest exponent value `(1 << EXP_BITS) - 1`.
50    const INFINITE_POWER: i32;
51
52    // Index (in bits) of the sign.
53    const SIGN_INDEX: usize;
54
55    // Smallest decimal exponent for a non-zero value.
56    const SMALLEST_POWER_OF_TEN: i32;
57
58    // Largest decimal exponent for a non-infinite value.
59    const LARGEST_POWER_OF_TEN: i32;
60
61    // Maximum mantissa for the fast-path (`1 << 53` for f64).
62    const MAX_MANTISSA_FAST_PATH: u64 = 2_u64 << Self::MANTISSA_EXPLICIT_BITS;
63
64    /// Convert integer into float through an as cast.
65    /// This is only called in the fast-path algorithm, and therefore
66    /// will not lose precision, since the value will always have
67    /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH.
68    fn from_u64(v: u64) -> Self;
69
70    /// Performs a raw transmutation from an integer.
71    fn from_u64_bits(v: u64) -> Self;
72
73    /// Get a small power-of-ten for fast-path multiplication.
74    fn pow10_fast_path(exponent: usize) -> Self;
75}
76
77impl RawFloat for f32 {
78    const INFINITY: Self = f32::INFINITY;
79    const NEG_INFINITY: Self = f32::NEG_INFINITY;
80    const NAN: Self = f32::NAN;
81    const NEG_NAN: Self = -f32::NAN;
82
83    const MANTISSA_EXPLICIT_BITS: usize = 23;
84    const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17;
85    const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
86    const MIN_EXPONENT_FAST_PATH: i64 = -10; // assuming FLT_EVAL_METHOD = 0
87    const MAX_EXPONENT_FAST_PATH: i64 = 10;
88    const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 17;
89    const MINIMUM_EXPONENT: i32 = -127;
90    const INFINITE_POWER: i32 = 0xFF;
91    const SIGN_INDEX: usize = 31;
92    const SMALLEST_POWER_OF_TEN: i32 = -65;
93    const LARGEST_POWER_OF_TEN: i32 = 38;
94
95    #[inline]
96    fn from_u64(v: u64) -> Self {
97        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
98        v as f32
99    }
100
101    #[inline]
102    fn from_u64_bits(v: u64) -> Self {
103        f32::from_bits((v & 0xFFFFFFFF) as u32)
104    }
105
106    #[inline]
107    fn pow10_fast_path(exponent: usize) -> Self {
108        static TABLE: [f32; 16] = [
109            1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.,
110        ];
111        TABLE[exponent & 15]
112    }
113}
114
115impl RawFloat for f64 {
116    const INFINITY: Self = f64::INFINITY;
117    const NEG_INFINITY: Self = f64::NEG_INFINITY;
118    const NAN: Self = f64::NAN;
119    const NEG_NAN: Self = -f64::NAN;
120
121    const MANTISSA_EXPLICIT_BITS: usize = 52;
122    const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -4;
123    const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23;
124    const MIN_EXPONENT_FAST_PATH: i64 = -22; // assuming FLT_EVAL_METHOD = 0
125    const MAX_EXPONENT_FAST_PATH: i64 = 22;
126    const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 37;
127    const MINIMUM_EXPONENT: i32 = -1023;
128    const INFINITE_POWER: i32 = 0x7FF;
129    const SIGN_INDEX: usize = 63;
130    const SMALLEST_POWER_OF_TEN: i32 = -342;
131    const LARGEST_POWER_OF_TEN: i32 = 308;
132
133    #[inline]
134    fn from_u64(v: u64) -> Self {
135        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
136        v as f64
137    }
138
139    #[inline]
140    fn from_u64_bits(v: u64) -> Self {
141        f64::from_bits(v)
142    }
143
144    #[inline]
145    fn pow10_fast_path(exponent: usize) -> Self {
146        static TABLE: [f64; 32] = [
147            1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
148            1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0.,
149        ];
150        TABLE[exponent & 31]
151    }
152}