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}