decompose_float/
ieee754.rs

1use crate::{Decompose, DecomposeResult};
2
3macro_rules! ieee754 {
4    ($fty: ty, $ity: ty, $exponent_width: literal, $mantissa_width: literal) => {
5        impl Decompose for $fty {
6            fn decompose(&self) -> DecomposeResult {
7                let uint = self.to_bits();
8                let is_neg = uint >= (1 << ($exponent_width + $mantissa_width));
9                let mut exp = ((uint >> $mantissa_width) & ((1 << $exponent_width) - 1)) as i32 - ((1 << ($exponent_width - 1)) - 1);
10                let mut mantissa = uint & ((1 << $mantissa_width) - 1);
11
12                if exp == -((1 << ($exponent_width - 1)) - 1) {
13                    exp += 1;
14
15                    if mantissa == 0 {
16                        if is_neg {
17                            return DecomposeResult::NegZero;
18                        }
19
20                        else {
21                            return DecomposeResult::Zero;
22                        }
23                    }
24
25                    let to_shift = $mantissa_width - mantissa.ilog2();
26                    mantissa <<= to_shift;
27                    exp -= to_shift as i32;
28                    mantissa -= 1 << $mantissa_width;
29                }
30
31                else if exp == 1 << ($exponent_width - 1) {
32                    if mantissa == 0 {
33                        if is_neg {
34                            return DecomposeResult::NegInfinity;
35                        }
36
37                        else {
38                            return DecomposeResult::Infinity;
39                        }
40                    }
41
42                    else {
43                        return DecomposeResult::NotANumber;
44                    }
45                }
46
47                let mut mantissa = mantissa as u128;
48                mantissa <<= (127 - $mantissa_width);
49                mantissa |= 1 << 127;
50                DecomposeResult::Normal { is_neg, exp, mantissa }
51            }
52        }
53
54        /// It implements `From<DecomposeResult>`, not `TryFrom<DecomposeResult>`.
55        /// If `DecomposeResult` is too big, it returns INFINITY or NEG_INFINITY instead
56        /// of throwing an overflow error. If it's too small, it returns 0.0 or -0.0 instead
57        /// of throwing an underflow error.
58        impl From<DecomposeResult> for $fty {
59            fn from(r: DecomposeResult) -> $fty {
60                match r {
61                    DecomposeResult::Normal { is_neg, exp, mantissa } => if 1 << ($exponent_width - 1) <= exp && is_neg {
62                        <$fty>::NEG_INFINITY
63                    } else if 1 << ($exponent_width - 1) <= exp {
64                        <$fty>::INFINITY
65                    } else if exp <= -((1 << ($exponent_width - 1)) + $mantissa_width - 1) && is_neg {
66                        -0.0
67                    } else if exp <= -((1 << ($exponent_width - 1)) + $mantissa_width - 1) {
68                        0.0
69                    } else if -((1 << ($exponent_width - 1)) + $mantissa_width - 2) <= exp && exp <= -((1 << ($exponent_width - 1)) - 1) {
70                        let is_neg = (is_neg as $ity) << ($exponent_width + $mantissa_width);
71                        let mut mantissa = (mantissa >> (127 - $mantissa_width)) as $ity;
72                        let to_shift = -(((1 << ($exponent_width - 1)) - 1) - 1) - exp;
73                        mantissa >>= to_shift;
74                        <$fty>::from_bits(is_neg | mantissa)
75                    } else {
76                        let is_neg = (is_neg as $ity) << ($exponent_width + $mantissa_width);
77                        let exp = ((exp + ((1 << ($exponent_width - 1)) - 1)) as $ity) << $mantissa_width;
78                        let mantissa = ((mantissa >> (127 - $mantissa_width)) & ((1 << $mantissa_width) - 1)) as $ity;
79                        <$fty>::from_bits(is_neg | exp | mantissa)
80                    },
81                    DecomposeResult::Zero => 0.0,
82                    DecomposeResult::NegZero => -0.0,
83                    DecomposeResult::Infinity => <$fty>::INFINITY,
84                    DecomposeResult::NegInfinity => <$fty>::NEG_INFINITY,
85                    DecomposeResult::NotANumber => <$fty>::NAN,
86                }
87            }
88        }
89    };
90}
91
92#[cfg(feature = "f16")]
93ieee754!(f16, u16, 5, 10);
94
95ieee754!(f32, u32, 8, 23);
96ieee754!(f64, u64, 11, 52);
97
98#[cfg(feature = "f128")]
99ieee754!(f128, u128, 15, 112);