dyadic/
lib.rs

1#![no_std]
2
3use core::cmp::*;
4use core::fmt;
5use core::ops::*;
6
7pub type DF = DyadicFraction;
8
9#[derive(Copy, Clone, Debug, Default)]
10pub struct DyadicFraction {
11    num: i32,
12    power: i8,
13}
14
15impl DyadicFraction {
16    pub const fn new(numerator: i32, denominator_power: i8) -> Self {
17        Self {
18            num: numerator,
19            power: denominator_power,
20        }
21        .canonical()
22    }
23
24    pub const fn zero() -> Self {
25        Self { num: 0, power: 0 }
26    }
27
28    pub const fn abs(self) -> Self {
29        Self::new(self.num.abs(), self.power)
30    }
31
32    pub const fn signum(self) -> Self {
33        Self::new(self.num.signum(), 0)
34    }
35
36    pub const fn copysign(self, sign: i32) -> Self {
37        if sign.signum() == self.num.signum() {
38            return self;
39        }
40        Self::new(-self.num, self.power)
41    }
42
43    pub const fn is_positive(self) -> bool {
44        self.num.is_positive()
45    }
46
47    pub const fn is_negative(self) -> bool {
48        self.num.is_negative()
49    }
50
51    pub const fn canonical(&self) -> Self {
52        let mut res = *self;
53        if res.num == 0 {
54            res.power = 0;
55        }
56        while res.power > 0 && (res.num & 1) == 0 {
57            res.power -= 1;
58            res.num >>= 1;
59        }
60        res
61    }
62
63    pub const fn round(&self, denominator_power: i8) -> Self {
64        let mut res = *self;
65        if res.num == 0 {
66            res.power = 0;
67        }
68        loop {
69            while res.power > 0 && (res.num & 1) == 0 {
70                res.power -= 1;
71                res.num >>= 1;
72            }
73            if res.power > denominator_power {
74                res.num &= !1;
75            } else {
76                break;
77            }
78        }
79        res
80    }
81
82    pub fn floor(&self) -> i32 {
83        let val = self.canonical();
84        let shift = val.power.abs();
85        if val.power <= 0 {
86            saturating_shl(val.num, shift)
87        } else {
88            saturating_shr(val.num, shift)
89        }
90    }
91
92    pub fn div_by_two(&self) -> Self {
93        let mut res = *self;
94        res.power = res.power.saturating_add(1);
95        res
96    }
97
98    pub fn mul_add(self, a: impl Into<Self>, b: impl Into<Self>) -> Self {
99        self * a.into() + b.into()
100    }
101
102    pub fn scale(self, a: impl Into<Self>) -> i32 {
103        self.canonical().mul(a.into()).floor()
104    }
105
106    pub fn pow(self, n: u8) -> Self {
107        if n == 0 {
108            return self.signum();
109        }
110        let mut res = self;
111        for _ in 0..n - 1 {
112            res *= self;
113        }
114        res
115    }
116
117    pub fn max(lhs: Self, rhs: Self) -> Self {
118        if lhs > rhs {
119            lhs
120        } else {
121            rhs
122        }
123    }
124
125    pub fn min(lhs: Self, rhs: Self) -> Self {
126        if lhs < rhs {
127            lhs
128        } else {
129            rhs
130        }
131    }
132
133    pub fn numerator(&self) -> i32 {
134        self.num
135    }
136
137    pub fn denominator_power(&self) -> i8 {
138        self.power
139    }
140
141    fn saturating_cross(self, other: Self) -> (i32, i32, i8) {
142        let (min_power, max_power) = if self.power > other.power {
143            (other.power, self.power)
144        } else {
145            (self.power, other.power)
146        };
147        (
148            saturating_shl(self.num, other.power - min_power),
149            saturating_shl(other.num, self.power - min_power),
150            max_power,
151        )
152    }
153}
154
155fn saturating_shl(num: i32, rhs: i8) -> i32 {
156    if rhs < 32 {
157        num.shl(rhs)
158    } else if num.is_positive() {
159        i32::MAX
160    } else {
161        i32::MIN
162    }
163}
164
165fn saturating_shr(num: i32, rhs: i8) -> i32 {
166    if rhs < 32 {
167        num.shr(rhs)
168    } else {
169        0
170    }
171}
172
173impl From<i32> for DyadicFraction {
174    fn from(num: i32) -> Self {
175        Self::new(num, 0)
176    }
177}
178
179impl From<isize> for DyadicFraction {
180    fn from(num: isize) -> Self {
181        Self::new(num as _, 0)
182    }
183}
184
185impl From<i16> for DyadicFraction {
186    fn from(num: i16) -> Self {
187        Self::new(num as _, 0)
188    }
189}
190
191impl From<u16> for DyadicFraction {
192    fn from(num: u16) -> Self {
193        Self::new(num as _, 0)
194    }
195}
196
197impl From<u8> for DyadicFraction {
198    fn from(num: u8) -> Self {
199        Self::new(num as _, 0)
200    }
201}
202
203impl From<i8> for DyadicFraction {
204    fn from(num: i8) -> Self {
205        Self::new(num as _, 0)
206    }
207}
208
209impl Add for DyadicFraction {
210    type Output = Self;
211
212    fn add(self, other: Self) -> Self {
213        let (fst, snd, power) = self.saturating_cross(other);
214        Self::new(fst.saturating_add(snd), power)
215    }
216}
217
218impl AddAssign for DyadicFraction {
219    fn add_assign(&mut self, rhs: Self) {
220        *self = *self + rhs;
221    }
222}
223
224impl Sub for DyadicFraction {
225    type Output = Self;
226
227    fn sub(self, other: Self) -> Self {
228        let (fst, snd, power) = self.saturating_cross(other);
229        Self::new(fst.saturating_sub(snd), power)
230    }
231}
232
233impl SubAssign for DyadicFraction {
234    fn sub_assign(&mut self, rhs: Self) {
235        *self = *self - rhs;
236    }
237}
238
239impl Mul for DyadicFraction {
240    type Output = Self;
241
242    fn mul(self, other: Self) -> Self {
243        Self::new(
244            self.num.saturating_mul(other.num),
245            self.power.saturating_add(other.power),
246        )
247        .canonical()
248    }
249}
250
251impl MulAssign for DyadicFraction {
252    fn mul_assign(&mut self, rhs: Self) {
253        *self = *self * rhs;
254    }
255}
256
257impl Neg for DyadicFraction {
258    type Output = Self;
259
260    fn neg(self) -> Self::Output {
261        Self::new(-self.num, self.power)
262    }
263}
264
265impl PartialEq for DyadicFraction {
266    fn eq(&self, other: &Self) -> bool {
267        let lhs = self.canonical();
268        let rhs = other.canonical();
269        lhs.power == rhs.power && lhs.num == rhs.num
270    }
271}
272
273impl Eq for DyadicFraction {}
274
275impl PartialOrd for DyadicFraction {
276    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
277        Some(self.cmp(other))
278    }
279}
280
281impl Ord for DyadicFraction {
282    fn cmp(&self, other: &Self) -> Ordering {
283        let delta = (*self - *other).numerator().signum();
284        if delta == 0 {
285            Ordering::Equal
286        } else if delta.is_positive() {
287            Ordering::Greater
288        } else {
289            Ordering::Less
290        }
291    }
292}
293
294impl fmt::Display for DyadicFraction {
295    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296        let val = self.canonical();
297        let shift = val.power.abs();
298        if val.power <= 0 {
299            write!(f, "{}", saturating_shl(val.num, shift))
300        } else {
301            write!(f, "{}/{}", val.num, saturating_shl(1, shift))
302        }
303    }
304}
305
306pub mod consts {
307    use super::*;
308
309    /// The full circle constant (τ)
310    ///
311    /// Equal to 2π.
312    pub const TAU: DyadicFraction = DyadicFraction::new(3217, 9);
313
314    /// Archimedes' constant (π)
315    pub const PI: DyadicFraction = DyadicFraction::new(3217, 10);
316
317    /// π/2
318    pub const FRAC_PI_2: DyadicFraction = DyadicFraction::new(3217, 11);
319
320    /// π/4
321    pub const FRAC_PI_4: DyadicFraction = DyadicFraction::new(3217, 12);
322
323    /// π/3
324    pub const FRAC_PI_3: DyadicFraction = DyadicFraction::new(68629, 16);
325
326    /// 1/π
327    pub const FRAC_1_PI: DyadicFraction = DyadicFraction::new(20861, 16);
328
329    /// 2/π
330    pub const FRAC_2_PI: DyadicFraction = DyadicFraction::new(20861, 15);
331
332    /// 2/sqrt(π)
333    pub const FRAC_2_SQRT_PI: DyadicFraction = DyadicFraction::new(73949, 16);
334
335    /// sqrt(2)
336    pub const SQRT_2: DyadicFraction = DyadicFraction::new(46341, 15);
337
338    /// 1/sqrt(2)
339    pub const FRAC_1_SQRT_2: DyadicFraction = DyadicFraction::new(46341, 16);
340
341    /// Euler's number (e)
342    pub const E: DyadicFraction = DyadicFraction::new(178145, 16);
343
344    /// log<sub>2</sub>(10)
345    pub const LOG2_10: DyadicFraction = DyadicFraction::new(108853, 15);
346
347    /// log<sub>2</sub>(e)
348    pub const LOG2_E: DyadicFraction = DyadicFraction::new(23637, 14);
349
350    /// log<sub>10</sub>(2)
351    pub const LOG10_2: DyadicFraction = DyadicFraction::new(1233, 12);
352
353    /// log<sub>10</sub>(e)
354    pub const LOG10_E: DyadicFraction = DyadicFraction::new(14231, 15);
355
356    /// ln(2)
357    pub const LN_2: DyadicFraction = DyadicFraction::new(22713, 15);
358
359    /// ln(10)
360    pub const LN_10: DyadicFraction = DyadicFraction::new(75451, 15);
361
362    /// Golden ratio
363    pub const PHI: DyadicFraction = DyadicFraction::new(13255, 13);
364
365    /// Supergolden ratio
366    pub const PSI: DyadicFraction = DyadicFraction::new(6003, 12);
367}