1use core::{fmt, ops::*};
2
3#[repr(transparent)]
4#[derive(Clone, Copy, PartialEq, Eq, Hash)]
5pub struct L32(u32);
6
7impl L32 {
8 pub const NAR: Self = Self(0xC0000000);
12
13 pub const ZERO: Self = Self(0x40000000);
15 pub const ONE: Self = Self(0);
17
18 #[inline]
20 pub const fn to_bits(self) -> u32 {
21 self.0
22 }
23
24 #[inline]
26 pub const fn from_bits(bits: u32) -> Self {
27 Self(bits)
28 }
29
30 #[inline]
34 pub fn sqrt(self) -> Self {
35 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 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 test(0xBFFFFFFF, 0x00000001, 0xC0000000);
153 test(0xBFFFFFFF, 0x80000001, 0x40000000);
154 test(0x3FFFFFFF, 0x00000001, 0x40000000);
155 test(0x3FFFFFFF, 0x80000001, 0xC0000000);
156 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 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 test(0xBFFFFFFF, 0x7FFFFFFF, 0xC0000000);
182 test(0xBFFFFFFF, 0xFFFFFFFF, 0x40000000);
183 test(0x3FFFFFFF, 0x7FFFFFFF, 0x40000000);
184 test(0x3FFFFFFF, 0xFFFFFFFF, 0xC0000000);
185 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 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 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}