log_num/
l32.rs

1use core::{fmt, ops::*};
2
3#[repr(transparent)]
4#[derive(Clone, Copy, PartialEq, Eq, Hash)]
5pub struct L32(u32);
6
7impl L32 {
8    /// Not a Real (NaR).
9    ///
10    /// Exceptional value for operations where the result cannot be expressed as a real number.
11    pub const NAR: Self = Self(0xC0000000);
12
13    /// The value 0.0
14    pub const ZERO: Self = Self(0x40000000);
15    /// The value 1.0
16    pub const ONE: Self = Self(0);
17
18    /// Raw transmutation to u32.
19    #[inline]
20    pub const fn to_bits(self) -> u32 {
21        self.0
22    }
23
24    /// Raw transmutation from u32.
25    #[inline]
26    pub const fn from_bits(bits: u32) -> Self {
27        Self(bits)
28    }
29
30    /// Calculates the square root.
31    ///
32    /// Returns NaR if the input is negative or NaR.
33    #[inline]
34    pub fn sqrt(self) -> Self {
35        // We don't care about the sign bit because if it's set the result will be overwritten
36        // with NaR anyway.
37        let exp = self.0 >> 1;
38        let exp_sign = self.0 & 0x40000000;
39        let mut res = Self(exp_sign | exp);
40
41        if self == Self::ZERO {
42            res = Self::ZERO;
43        }
44        if self.0 & 0x80000000 != 0 {
45            res = Self::NAR;
46        }
47
48        res
49    }
50}
51
52impl fmt::Debug for L32 {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        // TODO: proper formatting
55        self.0.fmt(f)
56    }
57}
58
59impl Mul<L32> for L32 {
60    type Output = Self;
61
62    #[inline]
63    fn mul(self, rhs: L32) -> Self {
64        let sign = (self.0 ^ rhs.0) & 0x80000000;
65        let exp = self.0.wrapping_add(rhs.0) & 0x7FFFFFFF;
66        let mut res = Self(sign | exp);
67
68        if self == Self::ZERO || rhs == Self::ZERO {
69            res = Self::ZERO;
70        }
71        if self == Self::NAR || rhs == Self::NAR {
72            res = Self::NAR;
73        }
74
75        res
76    }
77}
78
79impl MulAssign<L32> for L32 {
80    #[inline]
81    fn mul_assign(&mut self, rhs: L32) {
82        *self = *self * rhs;
83    }
84}
85
86impl Div<L32> for L32 {
87    type Output = L32;
88
89    #[inline]
90    fn div(self, rhs: L32) -> Self::Output {
91        let sign = (self.0 ^ rhs.0) & 0x80000000;
92        let exp = self.0.wrapping_sub(rhs.0) & 0x7FFFFFFF;
93        let mut res = Self(sign | exp);
94
95        if self == Self::ZERO {
96            res = Self::ZERO;
97        }
98        if self == Self::NAR || rhs == Self::NAR || rhs == Self::ZERO {
99            res = Self::NAR;
100        }
101
102        res
103    }
104}
105
106impl DivAssign<L32> for L32 {
107    #[inline]
108    fn div_assign(&mut self, rhs: L32) {
109        *self = *self / rhs;
110    }
111}
112
113impl Default for L32 {
114    #[inline]
115    fn default() -> Self {
116        Self::ZERO
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn sqrt() {
126        assert_eq!(L32::NAR.sqrt(), L32::NAR);
127        assert_eq!(L32(0x80000000).sqrt(), L32::NAR);
128        assert_eq!(L32(0x80000001).sqrt(), L32::NAR);
129        assert_eq!(L32(0x81234567).sqrt(), L32::NAR);
130        assert_eq!(L32(0xF3FCFEF3).sqrt(), L32::NAR);
131        assert_eq!(L32(0xFFFFFFFF).sqrt(), L32::NAR);
132
133        assert_eq!(L32(0x00000000).sqrt(), L32(0x00000000));
134        assert_eq!(L32(0x00000001).sqrt(), L32(0x00000000));
135        assert_eq!(L32(0x00800000).sqrt(), L32(0x00400000));
136        assert_eq!(L32(0x00800001).sqrt(), L32(0x00400000));
137        assert_eq!(L32(0x3FFFFFFF).sqrt(), L32(0x1FFFFFFF));
138        assert_eq!(L32(0x70006101).sqrt(), L32(0x78003080));
139        assert_eq!(L32(0x7FFFFFFF).sqrt(), L32(0x7FFFFFFF));
140        assert_eq!(L32(0x40000001).sqrt(), L32(0x60000000));
141        assert_eq!(L32(0x60000000).sqrt(), L32(0x70000000));
142    }
143
144    #[test]
145    fn mul() {
146        fn test(a: u32, b: u32, res: u32) {
147            assert_eq!(L32(a) * L32(b), L32(res));
148            assert_eq!(L32(b) * L32(a), L32(res));
149        }
150
151        // Overflow
152        test(0xBFFFFFFF, 0x00000001, 0xC0000000);
153        test(0xBFFFFFFF, 0x80000001, 0x40000000);
154        test(0x3FFFFFFF, 0x00000001, 0x40000000);
155        test(0x3FFFFFFF, 0x80000001, 0xC0000000);
156        // Multiply by 0
157        test(0xBFFFFFFF, 0x40000000, 0x40000000);
158        test(0x3FFFFFFF, 0x40000000, 0x40000000);
159        test(0x00000000, 0x40000000, 0x40000000);
160        test(0x80000000, 0x40000000, 0x40000000);
161        test(0xDEADBEEF, 0x40000000, 0x40000000);
162        // NaR preservation
163        test(0xDEADBEEF, 0xC0000000, 0xC0000000);
164        test(0x00000000, 0xC0000000, 0xC0000000);
165        test(0x80000000, 0xC0000000, 0xC0000000);
166        test(0x40000000, 0xC0000000, 0xC0000000);
167
168        test(0xBFFFFFFF, 0x80000000, 0x3FFFFFFF);
169        test(0x7FFFFFFF, 0x00000001, 0x00000000);
170        test(0xFFFFFFFF, 0x00000001, 0x80000000);
171        test(0xDEADBEEF, 0xBEEFDEAD, 0x1D9D9D9C);
172    }
173
174    #[test]
175    fn div() {
176        fn test(a: u32, b: u32, res: u32) {
177            assert_eq!(L32(a) / L32(b), L32(res));
178        }
179
180        // Overflow
181        test(0xBFFFFFFF, 0x7FFFFFFF, 0xC0000000);
182        test(0xBFFFFFFF, 0xFFFFFFFF, 0x40000000);
183        test(0x3FFFFFFF, 0x7FFFFFFF, 0x40000000);
184        test(0x3FFFFFFF, 0xFFFFFFFF, 0xC0000000);
185        // 0/x
186        test(0x40000000, 0xBFFFFFFF, 0x40000000);
187        test(0x40000000, 0x3FFFFFFF, 0x40000000);
188        test(0x40000000, 0x00000000, 0x40000000);
189        test(0x40000000, 0x80000000, 0x40000000);
190        test(0x40000000, 0xDEADBEEF, 0x40000000);
191        test(0x40000000, 0x00000001, 0x40000000);
192        // NaR preservation
193        test(0xDEADBEEF, 0xC0000000, 0xC0000000);
194        test(0x00000000, 0xC0000000, 0xC0000000);
195        test(0x80000000, 0xC0000000, 0xC0000000);
196        test(0xC0000000, 0xDEADBEEF, 0xC0000000);
197        test(0xC0000000, 0x00000000, 0xC0000000);
198        test(0xC0000000, 0x80000000, 0xC0000000);
199        // Division by 0
200        test(0xBFFFFFFF, 0x40000000, 0xC0000000);
201        test(0x3FFFFFFF, 0x40000000, 0xC0000000);
202        test(0x00000000, 0x40000000, 0xC0000000);
203        test(0x80000000, 0x40000000, 0xC0000000);
204        test(0xDEADBEEF, 0x40000000, 0xC0000000);
205        test(0x00000001, 0x40000000, 0xC0000000);
206
207        test(0xBFFFFFFF, 0x80000000, 0x3FFFFFFF);
208        test(0x00000000, 0x00000001, 0x7FFFFFFF);
209        test(0x80000000, 0x00000001, 0xFFFFFFFF);
210        test(0xDEADBEEF, 0xBEEFDEAD, 0x1FBDE042);
211    }
212}