Skip to main content

libm/math/support/
float_traits.rs

1#![allow(unknown_lints)] // FIXME(msrv) we shouldn't need this
2
3use core::{fmt, mem, ops};
4
5use super::int_traits::{CastFrom, Int, MinInt};
6
7/// Trait for some basic operations on floats
8// #[allow(dead_code)]
9#[allow(dead_code)] // Some constants are only used with tests
10pub trait Float:
11    Copy
12    + fmt::Debug
13    + PartialEq
14    + PartialOrd
15    + ops::AddAssign
16    + ops::MulAssign
17    + ops::Add<Output = Self>
18    + ops::Sub<Output = Self>
19    + ops::Mul<Output = Self>
20    + ops::Div<Output = Self>
21    + ops::Rem<Output = Self>
22    + ops::Neg<Output = Self>
23    + 'static
24{
25    /// A uint of the same width as the float
26    type Int: Int<OtherSign = Self::SignedInt, Unsigned = Self::Int>;
27
28    /// A int of the same width as the float
29    type SignedInt: Int
30        + MinInt<OtherSign = Self::Int, Unsigned = Self::Int>
31        + ops::Neg<Output = Self::SignedInt>;
32
33    const ZERO: Self;
34    const NEG_ZERO: Self;
35    const ONE: Self;
36    const NEG_ONE: Self;
37    const INFINITY: Self;
38    const NEG_INFINITY: Self;
39    const NAN: Self;
40    const NEG_NAN: Self;
41    const MAX: Self;
42    const MIN: Self;
43    const EPSILON: Self;
44    const PI: Self;
45    const NEG_PI: Self;
46    const FRAC_PI_2: Self;
47
48    const MIN_POSITIVE_NORMAL: Self;
49
50    /// The bitwidth of the float type
51    const BITS: u32;
52
53    /// The bitwidth of the significand
54    const SIG_BITS: u32;
55
56    /// The bitwidth of the exponent
57    const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1;
58
59    /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite
60    /// representation.
61    ///
62    /// This shifted fully right, use `EXP_MASK` for the shifted value.
63    const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1;
64
65    /// The exponent bias value
66    const EXP_BIAS: u32 = Self::EXP_SAT >> 1;
67
68    /// Maximum unbiased exponent value.
69    const EXP_MAX: i32 = Self::EXP_BIAS as i32;
70
71    /// Minimum *NORMAL* unbiased exponent value.
72    const EXP_MIN: i32 = -(Self::EXP_MAX - 1);
73
74    /// Minimum subnormal exponent value.
75    const EXP_MIN_SUBNORM: i32 = Self::EXP_MIN - Self::SIG_BITS as i32;
76
77    /// A mask for the sign bit
78    const SIGN_MASK: Self::Int;
79
80    /// A mask for the significand
81    const SIG_MASK: Self::Int;
82
83    /// A mask for the exponent
84    const EXP_MASK: Self::Int;
85
86    /// The implicit bit of the float format
87    const IMPLICIT_BIT: Self::Int;
88
89    /// Returns `self` transmuted to `Self::Int`
90    fn to_bits(self) -> Self::Int;
91
92    /// Returns `self` transmuted to `Self::SignedInt`
93    #[allow(dead_code)]
94    fn to_bits_signed(self) -> Self::SignedInt {
95        self.to_bits().signed()
96    }
97
98    /// Check bitwise equality.
99    #[allow(dead_code)]
100    fn biteq(self, rhs: Self) -> bool {
101        self.to_bits() == rhs.to_bits()
102    }
103
104    /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
105    /// represented in multiple different ways.
106    ///
107    /// This method returns `true` if two NaNs are compared. Use [`biteq`](Self::biteq) instead
108    /// if `NaN` should not be treated separately.
109    #[allow(dead_code)]
110    fn eq_repr(self, rhs: Self) -> bool {
111        if self.is_nan() && rhs.is_nan() {
112            true
113        } else {
114            self.biteq(rhs)
115        }
116    }
117
118    /// Returns true if the value is NaN.
119    fn is_nan(self) -> bool;
120
121    /// Returns true if the value is +inf or -inf.
122    fn is_infinite(self) -> bool;
123
124    /// Returns true if the sign is negative. Extracts the sign bit regardless of zero or NaN.
125    fn is_sign_negative(self) -> bool;
126
127    /// Returns true if the sign is positive. Extracts the sign bit regardless of zero or NaN.
128    fn is_sign_positive(self) -> bool {
129        !self.is_sign_negative()
130    }
131
132    /// Returns if `self` is subnormal.
133    #[allow(dead_code)]
134    fn is_subnormal(self) -> bool {
135        (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO
136    }
137
138    /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero.
139    fn ex(self) -> u32 {
140        u32::cast_from(self.to_bits() >> Self::SIG_BITS) & Self::EXP_SAT
141    }
142
143    /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero.
144    fn exp_unbiased(self) -> i32 {
145        self.ex().signed() - (Self::EXP_BIAS as i32)
146    }
147
148    /// Returns the significand with no implicit bit (or the "fractional" part)
149    #[allow(dead_code)]
150    fn frac(self) -> Self::Int {
151        self.to_bits() & Self::SIG_MASK
152    }
153
154    /// Returns a `Self::Int` transmuted back to `Self`
155    fn from_bits(a: Self::Int) -> Self;
156
157    /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position.
158    fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self {
159        let sign = if negative {
160            Self::Int::ONE
161        } else {
162            Self::Int::ZERO
163        };
164        Self::from_bits(
165            (sign << (Self::BITS - 1))
166                | (Self::Int::cast_from(exponent & Self::EXP_SAT) << Self::SIG_BITS)
167                | (significand & Self::SIG_MASK),
168        )
169    }
170
171    #[allow(dead_code)]
172    fn abs(self) -> Self;
173
174    /// Returns a number composed of the magnitude of self and the sign of sign.
175    fn copysign(self, other: Self) -> Self;
176
177    /// Fused multiply add, rounding once.
178    fn fma(self, y: Self, z: Self) -> Self;
179
180    /// Returns (normalized exponent, normalized significand)
181    #[allow(dead_code)]
182    fn normalize(significand: Self::Int) -> (i32, Self::Int);
183
184    /// Returns a number that represents the sign of self.
185    #[allow(dead_code)]
186    fn signum(self) -> Self {
187        if self.is_nan() {
188            self
189        } else {
190            Self::ONE.copysign(self)
191        }
192    }
193
194    /// Make a best-effort attempt to canonicalize the number. Note that this is allowed
195    /// to be a nop and does not always quiet sNaNs.
196    fn canonicalize(self) -> Self {
197        // FIXME: LLVM often removes this. We should determine whether we can remove the operation,
198        // or switch to something based on `llvm.canonicalize` (which has crashes,
199        // <https://github.com/llvm/llvm-project/issues/32650>).
200        self * Self::ONE
201    }
202}
203
204/// Access the associated `Int` type from a float (helper to avoid ambiguous associated types).
205pub type IntTy<F> = <F as Float>::Int;
206
207macro_rules! float_impl {
208    (
209        $ty:ident,
210        $ity:ident,
211        $sity:ident,
212        $bits:expr,
213        $significand_bits:expr,
214        $from_bits:path,
215        $to_bits:path,
216        $fma_fn:ident,
217        $fma_intrinsic:ident
218    ) => {
219        impl Float for $ty {
220            type Int = $ity;
221            type SignedInt = $sity;
222
223            const ZERO: Self = 0.0;
224            const NEG_ZERO: Self = -0.0;
225            const ONE: Self = 1.0;
226            const NEG_ONE: Self = -1.0;
227            const INFINITY: Self = Self::INFINITY;
228            const NEG_INFINITY: Self = Self::NEG_INFINITY;
229            const NAN: Self = Self::NAN;
230            // NAN isn't guaranteed to be positive but it usually is. We only use this for
231            // tests.
232            const NEG_NAN: Self = $from_bits($to_bits(Self::NAN) | Self::SIGN_MASK);
233            const MAX: Self = -Self::MIN;
234            // Sign bit set, saturated mantissa, saturated exponent with last bit zeroed
235            const MIN: Self = $from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS));
236            const EPSILON: Self = <$ty>::EPSILON;
237
238            // Exponent is a 1 in the LSB
239            const MIN_POSITIVE_NORMAL: Self = $from_bits(1 << Self::SIG_BITS);
240
241            const PI: Self = core::$ty::consts::PI;
242            const NEG_PI: Self = -Self::PI;
243            const FRAC_PI_2: Self = core::$ty::consts::FRAC_PI_2;
244
245            const BITS: u32 = $bits;
246            const SIG_BITS: u32 = $significand_bits;
247
248            const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1);
249            const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1;
250            const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK);
251            const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS;
252
253            fn to_bits(self) -> Self::Int {
254                self.to_bits()
255            }
256            fn is_nan(self) -> bool {
257                self.is_nan()
258            }
259            fn is_infinite(self) -> bool {
260                self.is_infinite()
261            }
262            fn is_sign_negative(self) -> bool {
263                self.is_sign_negative()
264            }
265            fn from_bits(a: Self::Int) -> Self {
266                Self::from_bits(a)
267            }
268            fn abs(self) -> Self {
269                cfg_if! {
270                    // FIXME(msrv): `abs` is available in `core` starting with 1.85.
271                    if #[cfg(intrinsics_enabled)] {
272                        self.abs()
273                    } else {
274                        super::super::generic::fabs(self)
275                    }
276                }
277            }
278            fn copysign(self, other: Self) -> Self {
279                cfg_if! {
280                    // FIXME(msrv): `copysign` is available in `core` starting with 1.85.
281                    if #[cfg(intrinsics_enabled)] {
282                        self.copysign(other)
283                    } else {
284                        super::super::generic::copysign(self, other)
285                    }
286                }
287            }
288            fn fma(self, y: Self, z: Self) -> Self {
289                cfg_if! {
290                    // fma is not yet available in `core`
291                    if #[cfg(intrinsics_enabled)] {
292                        // FIXME(msrv,bench): once our benchmark rustc version is above the
293                        // 2022-09-23 nightly, this can be removed.
294                        #[allow(unused_unsafe)]
295                        unsafe { core::intrinsics::$fma_intrinsic(self, y, z) }
296                    } else {
297                        super::super::$fma_fn(self, y, z)
298                    }
299                }
300            }
301            fn normalize(significand: Self::Int) -> (i32, Self::Int) {
302                let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS);
303                (
304                    1i32.wrapping_sub(shift as i32),
305                    significand << shift as Self::Int,
306                )
307            }
308        }
309    };
310}
311
312#[cfg(f16_enabled)]
313float_impl!(
314    f16,
315    u16,
316    i16,
317    16,
318    10,
319    f16::from_bits,
320    f16::to_bits,
321    fmaf16,
322    fmaf16
323);
324impl Float for f32 {
    type Int = u32;
    type SignedInt = i32;
    const ZERO: Self = 0.0;
    const NEG_ZERO: Self = -0.0;
    const ONE: Self = 1.0;
    const NEG_ONE: Self = -1.0;
    const INFINITY: Self = Self::INFINITY;
    const NEG_INFINITY: Self = Self::NEG_INFINITY;
    const NAN: Self = Self::NAN;
    const NEG_NAN: Self =
        f32_from_bits(f32_to_bits(Self::NAN) | Self::SIGN_MASK);
    const MAX: Self = -Self::MIN;
    const MIN: Self = f32_from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS));
    const EPSILON: Self = <f32>::EPSILON;
    const MIN_POSITIVE_NORMAL: Self = f32_from_bits(1 << Self::SIG_BITS);
    const PI: Self = core::f32::consts::PI;
    const NEG_PI: Self = -Self::PI;
    const FRAC_PI_2: Self = core::f32::consts::FRAC_PI_2;
    const BITS: u32 = 32;
    const SIG_BITS: u32 = 23;
    const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1);
    const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1;
    const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK);
    const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS;
    fn to_bits(self) -> Self::Int { self.to_bits() }
    fn is_nan(self) -> bool { self.is_nan() }
    fn is_infinite(self) -> bool { self.is_infinite() }
    fn is_sign_negative(self) -> bool { self.is_sign_negative() }
    fn from_bits(a: Self::Int) -> Self { Self::from_bits(a) }
    fn abs(self) -> Self { super::super::generic::fabs(self) }
    fn copysign(self, other: Self) -> Self {
        super::super::generic::copysign(self, other)
    }
    fn fma(self, y: Self, z: Self) -> Self { super::super::fmaf(self, y, z) }
    fn normalize(significand: Self::Int) -> (i32, Self::Int) {
        let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS);
        (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int)
    }
}float_impl!(
325    f32,
326    u32,
327    i32,
328    32,
329    23,
330    f32_from_bits,
331    f32_to_bits,
332    fmaf,
333    fmaf32
334);
335impl Float for f64 {
    type Int = u64;
    type SignedInt = i64;
    const ZERO: Self = 0.0;
    const NEG_ZERO: Self = -0.0;
    const ONE: Self = 1.0;
    const NEG_ONE: Self = -1.0;
    const INFINITY: Self = Self::INFINITY;
    const NEG_INFINITY: Self = Self::NEG_INFINITY;
    const NAN: Self = Self::NAN;
    const NEG_NAN: Self =
        f64_from_bits(f64_to_bits(Self::NAN) | Self::SIGN_MASK);
    const MAX: Self = -Self::MIN;
    const MIN: Self = f64_from_bits(Self::Int::MAX & !(1 << Self::SIG_BITS));
    const EPSILON: Self = <f64>::EPSILON;
    const MIN_POSITIVE_NORMAL: Self = f64_from_bits(1 << Self::SIG_BITS);
    const PI: Self = core::f64::consts::PI;
    const NEG_PI: Self = -Self::PI;
    const FRAC_PI_2: Self = core::f64::consts::FRAC_PI_2;
    const BITS: u32 = 64;
    const SIG_BITS: u32 = 52;
    const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1);
    const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1;
    const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK);
    const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS;
    fn to_bits(self) -> Self::Int { self.to_bits() }
    fn is_nan(self) -> bool { self.is_nan() }
    fn is_infinite(self) -> bool { self.is_infinite() }
    fn is_sign_negative(self) -> bool { self.is_sign_negative() }
    fn from_bits(a: Self::Int) -> Self { Self::from_bits(a) }
    fn abs(self) -> Self { super::super::generic::fabs(self) }
    fn copysign(self, other: Self) -> Self {
        super::super::generic::copysign(self, other)
    }
    fn fma(self, y: Self, z: Self) -> Self { super::super::fma(self, y, z) }
    fn normalize(significand: Self::Int) -> (i32, Self::Int) {
        let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS);
        (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int)
    }
}float_impl!(
336    f64,
337    u64,
338    i64,
339    64,
340    52,
341    f64_from_bits,
342    f64_to_bits,
343    fma,
344    fmaf64
345);
346#[cfg(f128_enabled)]
347float_impl!(
348    f128,
349    u128,
350    i128,
351    128,
352    112,
353    f128::from_bits,
354    f128::to_bits,
355    fmaf128,
356    fmaf128
357);
358
359/* FIXME(msrv): vendor some things that are not const stable at our MSRV */
360
361/// `f32::from_bits`
362#[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust
363pub const fn f32_from_bits(bits: u32) -> f32 {
364    // SAFETY: POD cast with no preconditions
365    unsafe { mem::transmute::<u32, f32>(bits) }
366}
367
368/// `f32::to_bits`
369#[allow(dead_code)] // workaround for false positive RUST-144060
370#[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust
371pub const fn f32_to_bits(x: f32) -> u32 {
372    // SAFETY: POD cast with no preconditions
373    unsafe { mem::transmute::<f32, u32>(x) }
374}
375
376/// `f64::from_bits`
377#[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust
378pub const fn f64_from_bits(bits: u64) -> f64 {
379    // SAFETY: POD cast with no preconditions
380    unsafe { mem::transmute::<u64, f64>(bits) }
381}
382
383/// `f64::to_bits`
384#[allow(dead_code)] // workaround for false positive RUST-144060
385#[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust
386pub const fn f64_to_bits(x: f64) -> u64 {
387    // SAFETY: POD cast with no preconditions
388    unsafe { mem::transmute::<f64, u64>(x) }
389}
390
391/// Trait for floats twice the bit width of another integer.
392pub trait DFloat: Float {
393    /// Float that is half the bit width of the floatthis trait is implemented for.
394    type H: HFloat<D = Self>;
395
396    /// Narrow the float type.
397    fn narrow(self) -> Self::H;
398}
399
400/// Trait for floats half the bit width of another float.
401pub trait HFloat: Float {
402    /// Float that is double the bit width of the float this trait is implemented for.
403    type D: DFloat<H = Self>;
404
405    /// Widen the float type.
406    fn widen(self) -> Self::D;
407}
408
409macro_rules! impl_d_float {
410    ($($X:ident $D:ident),*) => {
411        $(
412            impl DFloat for $D {
413                type H = $X;
414
415                fn narrow(self) -> Self::H {
416                    self as $X
417                }
418            }
419        )*
420    };
421}
422
423macro_rules! impl_h_float {
424    ($($H:ident $X:ident),*) => {
425        $(
426            impl HFloat for $H {
427                type D = $X;
428
429                fn widen(self) -> Self::D {
430                    self as $X
431                }
432            }
433        )*
434    };
435}
436
437impl DFloat for f64 {
    type H = f32;
    fn narrow(self) -> Self::H { self as f32 }
}impl_d_float!(f32 f64);
438#[cfg(f16_enabled)]
439impl_d_float!(f16 f32);
440#[cfg(f128_enabled)]
441impl_d_float!(f64 f128);
442
443impl HFloat for f32 {
    type D = f64;
    fn widen(self) -> Self::D { self as f64 }
}impl_h_float!(f32 f64);
444#[cfg(f16_enabled)]
445impl_h_float!(f16 f32);
446#[cfg(f128_enabled)]
447impl_h_float!(f64 f128);
448
449#[cfg(test)]
450mod tests {
451    use super::*;
452
453    #[test]
454    #[cfg(f16_enabled)]
455    fn check_f16() {
456        // Constants
457        assert_eq!(f16::EXP_SAT, 0b11111);
458        assert_eq!(f16::EXP_BIAS, 15);
459        assert_eq!(f16::EXP_MAX, 15);
460        assert_eq!(f16::EXP_MIN, -14);
461        assert_eq!(f16::EXP_MIN_SUBNORM, -24);
462
463        // `exp_unbiased`
464        assert_eq!(f16::FRAC_PI_2.exp_unbiased(), 0);
465        assert_eq!((1.0f16 / 2.0).exp_unbiased(), -1);
466        assert_eq!(f16::MAX.exp_unbiased(), 15);
467        assert_eq!(f16::MIN.exp_unbiased(), 15);
468        assert_eq!(f16::MIN_POSITIVE.exp_unbiased(), -14);
469        // This is a convenience method and not ldexp, `exp_unbiased` does not return correct
470        // results for zero and subnormals.
471        assert_eq!(f16::ZERO.exp_unbiased(), -15);
472        assert_eq!(f16::from_bits(0x1).exp_unbiased(), -15);
473        assert_eq!(f16::MIN_POSITIVE, f16::MIN_POSITIVE_NORMAL);
474
475        // `from_parts`
476        assert_biteq!(f16::from_parts(true, f16::EXP_BIAS, 0), -1.0f16);
477        assert_biteq!(f16::from_parts(false, 0, 1), f16::from_bits(0x1));
478    }
479
480    #[test]
481    fn check_f32() {
482        // Constants
483        assert_eq!(f32::EXP_SAT, 0b11111111);
484        assert_eq!(f32::EXP_BIAS, 127);
485        assert_eq!(f32::EXP_MAX, 127);
486        assert_eq!(f32::EXP_MIN, -126);
487        assert_eq!(f32::EXP_MIN_SUBNORM, -149);
488
489        // `exp_unbiased`
490        assert_eq!(f32::FRAC_PI_2.exp_unbiased(), 0);
491        assert_eq!((1.0f32 / 2.0).exp_unbiased(), -1);
492        assert_eq!(f32::MAX.exp_unbiased(), 127);
493        assert_eq!(f32::MIN.exp_unbiased(), 127);
494        assert_eq!(f32::MIN_POSITIVE.exp_unbiased(), -126);
495        // This is a convenience method and not ldexp, `exp_unbiased` does not return correct
496        // results for zero and subnormals.
497        assert_eq!(f32::ZERO.exp_unbiased(), -127);
498        assert_eq!(f32::from_bits(0x1).exp_unbiased(), -127);
499        assert_eq!(f32::MIN_POSITIVE, f32::MIN_POSITIVE_NORMAL);
500
501        // `from_parts`
502        assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32);
503        assert_biteq!(
504            f32::from_parts(false, 10 + f32::EXP_BIAS, 0),
505            hf32!("0x1p10")
506        );
507        assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1));
508    }
509
510    #[test]
511    fn check_f64() {
512        // Constants
513        assert_eq!(f64::EXP_SAT, 0b11111111111);
514        assert_eq!(f64::EXP_BIAS, 1023);
515        assert_eq!(f64::EXP_MAX, 1023);
516        assert_eq!(f64::EXP_MIN, -1022);
517        assert_eq!(f64::EXP_MIN_SUBNORM, -1074);
518
519        // `exp_unbiased`
520        assert_eq!(f64::FRAC_PI_2.exp_unbiased(), 0);
521        assert_eq!((1.0f64 / 2.0).exp_unbiased(), -1);
522        assert_eq!(f64::MAX.exp_unbiased(), 1023);
523        assert_eq!(f64::MIN.exp_unbiased(), 1023);
524        assert_eq!(f64::MIN_POSITIVE.exp_unbiased(), -1022);
525        // This is a convenience method and not ldexp, `exp_unbiased` does not return correct
526        // results for zero and subnormals.
527        assert_eq!(f64::ZERO.exp_unbiased(), -1023);
528        assert_eq!(f64::from_bits(0x1).exp_unbiased(), -1023);
529        assert_eq!(f64::MIN_POSITIVE, f64::MIN_POSITIVE_NORMAL);
530
531        // `from_parts`
532        assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64);
533        assert_biteq!(
534            f64::from_parts(false, 10 + f64::EXP_BIAS, 0),
535            hf64!("0x1p10")
536        );
537        assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1));
538    }
539
540    #[test]
541    #[cfg(f128_enabled)]
542    fn check_f128() {
543        // Constants
544        assert_eq!(f128::EXP_SAT, 0b111111111111111);
545        assert_eq!(f128::EXP_BIAS, 16383);
546        assert_eq!(f128::EXP_MAX, 16383);
547        assert_eq!(f128::EXP_MIN, -16382);
548        assert_eq!(f128::EXP_MIN_SUBNORM, -16494);
549
550        // `exp_unbiased`
551        assert_eq!(f128::FRAC_PI_2.exp_unbiased(), 0);
552        assert_eq!((1.0f128 / 2.0).exp_unbiased(), -1);
553        assert_eq!(f128::MAX.exp_unbiased(), 16383);
554        assert_eq!(f128::MIN.exp_unbiased(), 16383);
555        assert_eq!(f128::MIN_POSITIVE.exp_unbiased(), -16382);
556        // This is a convenience method and not ldexp, `exp_unbiased` does not return correct
557        // results for zero and subnormals.
558        assert_eq!(f128::ZERO.exp_unbiased(), -16383);
559        assert_eq!(f128::from_bits(0x1).exp_unbiased(), -16383);
560        assert_eq!(f128::MIN_POSITIVE, f128::MIN_POSITIVE_NORMAL);
561
562        // `from_parts`
563        assert_biteq!(f128::from_parts(true, f128::EXP_BIAS, 0), -1.0f128);
564        assert_biteq!(f128::from_parts(false, 0, 1), f128::from_bits(0x1));
565    }
566}