lilliput_float/
repr.rs

1use crate::floats::{F16, F24, F32, F40, F48, F56, F64, F8};
2
3pub trait FpRepr: Sized + Copy + PartialEq + PartialOrd {
4    type Bits;
5
6    const ZERO: Self;
7    const ONE: Self;
8
9    const MIN: Self;
10    const MAX: Self;
11    const MIN_POSITIVE: Self;
12
13    const INFINITY: Self;
14    const NEG_INFINITY: Self;
15
16    const BITS: u32;
17    const SIGN_BITS: u32;
18    const EXPONENT_BITS: u32;
19    const SIGNIFICAND_BITS: u32;
20
21    const EXPONENT_MAX: Self::Bits;
22    const EXPONENT_BIAS: Self::Bits;
23
24    const SIGN_MASK: Self::Bits;
25    const EXPONENT_MASK: Self::Bits;
26    const SIGNIFICAND_MASK: Self::Bits;
27
28    const IMPLICIT_BIT: Self::Bits;
29}
30
31macro_rules! impl_float_repr {
32    ($t:ty, bytes: [u8; $bytes:expr], bits: $bits:ty, sign: 1, exponent: $exponent:expr, significand: $significand:expr) => {
33        impl FpRepr for $t {
34            type Bits = $bits;
35
36            const ZERO: Self = Self(0);
37            const ONE: Self = Self((Self::EXPONENT_MASK >> 1) & Self::EXPONENT_MASK);
38
39            const MIN: Self = Self(
40                Self::SIGN_MASK
41                    | ((Self::EXPONENT_MASK << 1) & Self::EXPONENT_MASK)
42                    | Self::SIGNIFICAND_MASK,
43            );
44            const MAX: Self =
45                Self(((Self::EXPONENT_MASK << 1) & Self::EXPONENT_MASK) | Self::SIGNIFICAND_MASK);
46            const MIN_POSITIVE: Self = Self(1 << Self::SIGNIFICAND_BITS);
47
48            const INFINITY: Self = Self(Self::EXPONENT_MASK);
49            const NEG_INFINITY: Self = Self(Self::SIGN_MASK | Self::EXPONENT_MASK);
50
51            const BITS: u32 = Self::SIGN_BITS + Self::EXPONENT_BITS + Self::SIGNIFICAND_BITS;
52            const SIGN_BITS: u32 = 1;
53            const EXPONENT_BITS: u32 = $exponent;
54            const SIGNIFICAND_BITS: u32 = $significand;
55
56            const EXPONENT_MAX: Self::Bits = (1 << Self::EXPONENT_BITS) - 1;
57            const EXPONENT_BIAS: Self::Bits = (Self::EXPONENT_MAX >> 1) as Self::Bits;
58
59            const SIGN_MASK: Self::Bits = 1 << (Self::BITS - 1);
60            const EXPONENT_MASK: Self::Bits = (Self::SIGN_MASK - 1) & !Self::SIGNIFICAND_MASK;
61            const SIGNIFICAND_MASK: Self::Bits = (1 << Self::SIGNIFICAND_BITS) - 1;
62            const IMPLICIT_BIT: Self::Bits = 1 << Self::SIGNIFICAND_BITS;
63        }
64    };
65}
66
67impl_float_repr!(F8, bytes: [u8; 1], bits: u8, sign: 1, exponent: 4, significand: 3);
68impl_float_repr!(F16, bytes: [u8; 2], bits: u16, sign: 1, exponent: 5, significand: 10);
69impl_float_repr!(F24, bytes: [u8; 3], bits: u32, sign: 1, exponent: 7, significand: 16);
70impl_float_repr!(F32, bytes: [u8; 4], bits: u32, sign: 1, exponent: 8, significand: 23);
71impl_float_repr!(F40, bytes: [u8; 5], bits: u64, sign: 1, exponent: 8, significand: 31);
72impl_float_repr!(F48, bytes: [u8; 6], bits: u64, sign: 1, exponent: 9, significand: 38);
73impl_float_repr!(F56, bytes: [u8; 7], bits: u64, sign: 1, exponent: 10, significand: 45);
74impl_float_repr!(F64, bytes: [u8; 8], bits: u64, sign: 1, exponent: 11, significand: 52);
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79
80    #[test]
81    fn f32_matches_native_behavior() {
82        assert_eq!(F32::ZERO, F32::from(0.0_f32));
83        assert_eq!(F32::ONE, F32::from(1.0_f32));
84        assert_eq!(F32::MIN, F32::from(f32::MIN));
85        assert_eq!(F32::MAX, F32::from(f32::MAX));
86        assert_eq!(F32::MIN_POSITIVE, F32::from(f32::MIN_POSITIVE));
87        assert_eq!(F32::INFINITY, F32::from(f32::INFINITY));
88        assert_eq!(F32::NEG_INFINITY, F32::from(f32::NEG_INFINITY));
89    }
90
91    #[test]
92    fn f64_matches_native_behavior() {
93        assert_eq!(F64::ZERO, F64::from(0.0_f64));
94        assert_eq!(F64::ONE, F64::from(1.0_f64));
95        assert_eq!(F64::MIN, F64::from(f64::MIN));
96        assert_eq!(F64::MAX, F64::from(f64::MAX));
97        assert_eq!(F64::MIN_POSITIVE, F64::from(f64::MIN_POSITIVE));
98        assert_eq!(F64::INFINITY, F64::from(f64::INFINITY));
99        assert_eq!(F64::NEG_INFINITY, F64::from(f64::NEG_INFINITY));
100    }
101}