1use std::cmp::Ordering;
2
3use crate::{
4 bits::FpToBits,
5 floats::{F16, F24, F32, F40, F48, F56, F64, F8},
6 repr::FpRepr,
7};
8
9macro_rules! impl_float_partial_eq_and_ord {
13 ($t:ty => unsigned: $unsigned:ty, signed: $signed:ty) => {
14 impl PartialEq for $t {
15 fn eq(&self, other: &Self) -> bool {
16 self.partial_cmp(other) == Some(Ordering::Equal)
17 }
18 }
19
20 impl PartialOrd for $t {
21 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
22 let sign_bit = <$t>::SIGN_MASK;
23 let abs_mask = sign_bit - 1;
24 let exponent_mask = <$t>::EXPONENT_MASK;
25 let inf_rep = exponent_mask;
26
27 let lhs = *self;
28 let rhs = *other;
29
30 let lhs_bits = lhs.to_bits();
31 let rhs_bits = rhs.to_bits();
32 let lhs_abs = lhs_bits & abs_mask;
33 let rhs_abs = rhs_bits & abs_mask;
34
35 if lhs_abs > inf_rep || rhs_abs > inf_rep {
37 return None;
38 }
39
40 if (lhs_abs | rhs_abs) == 0 {
42 return Some(Ordering::Equal);
43 }
44
45 let lhs_srep: $signed = lhs_bits as $signed;
46 let rhs_srep: $signed = rhs_bits as $signed;
47
48 if (lhs_srep & rhs_srep) >= 0 {
51 if lhs_srep < rhs_srep {
52 Some(Ordering::Less)
53 } else if lhs_srep == rhs_srep {
54 Some(Ordering::Equal)
55 } else {
56 Some(Ordering::Greater)
57 }
58 } else if lhs_srep > rhs_srep {
63 Some(Ordering::Less)
64 } else if lhs_srep == rhs_srep {
65 Some(Ordering::Equal)
66 } else {
67 Some(Ordering::Greater)
68 }
69 }
70 }
71 };
72}
73
74impl_float_partial_eq_and_ord!(F8 => unsigned: u8, signed: i8);
75impl_float_partial_eq_and_ord!(F16 => unsigned: u16, signed: i16);
76impl_float_partial_eq_and_ord!(F24 => unsigned: u32, signed: i32);
77impl_float_partial_eq_and_ord!(F32 => unsigned: u32, signed: i32);
78impl_float_partial_eq_and_ord!(F40 => unsigned: u64, signed: i64);
79impl_float_partial_eq_and_ord!(F48 => unsigned: u64, signed: i64);
80impl_float_partial_eq_and_ord!(F56 => unsigned: u64, signed: i64);
81impl_float_partial_eq_and_ord!(F64 => unsigned: u64, signed: i64);
82
83#[cfg(test)]
84mod tests {
85 use proptest::prelude::*;
86
87 use super::*;
88
89 proptest! {
90 #[test]
91 fn f32_matches_native_behavior(native_lhs in f32::arbitrary(), native_rhs in f32::arbitrary()) {
92 let (lhs, rhs) = (F32::from(native_lhs), F32::from(native_rhs));
93 let actual = lhs.partial_cmp(&rhs);
94 let expected = native_lhs.partial_cmp(&native_rhs);
95 prop_assert_eq!(actual, expected);
96 }
97
98 #[test]
99 fn f64_matches_native_behavior(native_lhs in f64::arbitrary(), native_rhs in f64::arbitrary()) {
100 let (lhs, rhs) = (F64::from(native_lhs), F64::from(native_rhs));
101 let actual = lhs.partial_cmp(&rhs);
102 let expected = native_lhs.partial_cmp(&native_rhs);
103 prop_assert_eq!(actual, expected);
104 }
105 }
106}