lilliput_float/
classify.rs1use std::num::FpCategory;
2
3use crate::bits::FpToBits;
4use crate::floats::{F16, F24, F32, F40, F48, F56, F64, F8};
5use crate::repr::FpRepr;
6use crate::PackedFloat;
7
8pub trait FpClassify: Sized {
9 fn classify(&self) -> FpCategory;
10
11 fn is_zero(&self) -> bool {
12 matches!(self.classify(), FpCategory::Zero)
13 }
14
15 fn is_nan(&self) -> bool {
16 matches!(self.classify(), FpCategory::Nan)
17 }
18
19 fn is_infinite(&self) -> bool {
20 matches!(self.classify(), FpCategory::Infinite)
21 }
22
23 fn is_subnormal(&self) -> bool {
24 matches!(self.classify(), FpCategory::Subnormal)
25 }
26
27 fn is_normal(&self) -> bool {
28 matches!(self.classify(), FpCategory::Normal)
29 }
30}
31
32macro_rules! impl_float_classify {
33 ($t:ty) => {
34 impl FpClassify for $t {
35 fn classify(&self) -> FpCategory {
36 let bits = self.to_bits();
37 let exponent_bits = bits & Self::EXPONENT_MASK;
38 let significand_bits = bits & Self::SIGNIFICAND_MASK;
39
40 match (exponent_bits, significand_bits) {
41 (Self::EXPONENT_MASK, 0) => FpCategory::Infinite,
42 (Self::EXPONENT_MASK, _) => FpCategory::Nan,
43 (0, 0) => FpCategory::Zero,
44 (0, _) => FpCategory::Subnormal,
45 _ => FpCategory::Normal,
46 }
47 }
48 }
49 };
50}
51
52impl_float_classify!(F8);
53impl_float_classify!(F16);
54impl_float_classify!(F24);
55impl_float_classify!(F32);
56impl_float_classify!(F40);
57impl_float_classify!(F48);
58impl_float_classify!(F56);
59impl_float_classify!(F64);
60
61impl FpClassify for PackedFloat {
62 fn classify(&self) -> FpCategory {
63 match self {
64 Self::F8(value) => value.classify(),
65 Self::F16(value) => value.classify(),
66 Self::F24(value) => value.classify(),
67 Self::F32(value) => value.classify(),
68 Self::F40(value) => value.classify(),
69 Self::F48(value) => value.classify(),
70 Self::F56(value) => value.classify(),
71 Self::F64(value) => value.classify(),
72 }
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use proptest::prelude::*;
79
80 use super::*;
81
82 proptest! {
83 #[test]
84 fn f32_matches_native_behavior(native in f32::arbitrary()) {
85 let subject = F32::from(native);
86 let actual = subject.classify();
87 let expected = native.classify();
88 prop_assert_eq!(actual, expected);
89 }
90
91 #[test]
92 fn f64_matches_native_behavior(native in f64::arbitrary()) {
93 let subject = F64::from(native);
94 let actual = subject.classify();
95 let expected = native.classify();
96 prop_assert_eq!(actual, expected);
97 }
98 }
99}