Skip to main content

dsp_fixedpoint/
ops.rs

1use core::{
2    iter,
3    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign},
4    ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign},
5    ops::{Neg, Not, Shl, ShlAssign, Shr, ShrAssign},
6};
7
8use crate::{Accu, Q, Shift};
9
10macro_rules! forward_unop {
11    ($tr:ident::$m:ident) => {
12        impl<T: $tr<Output = T>, A, const F: i8> $tr for Q<T, A, F> {
13            type Output = Self;
14            #[inline]
15            fn $m(self) -> Self::Output {
16                Self::new(<T as $tr>::$m(self.inner))
17            }
18        }
19    };
20}
21forward_unop!(Neg::neg);
22forward_unop!(Not::not);
23
24macro_rules! forward_sh_op {
25    ($tr:ident::$m:ident) => {
26        impl<U, T: $tr<U, Output = T>, A, const F: i8> $tr<U> for Q<T, A, F> {
27            type Output = Self;
28            #[inline]
29            fn $m(self, rhs: U) -> Self::Output {
30                Self::new(<T as $tr<U>>::$m(self.inner, rhs))
31            }
32        }
33    };
34}
35forward_sh_op!(Shr::shr);
36forward_sh_op!(Shl::shl);
37
38macro_rules! forward_sh_assign_op {
39    ($tr:ident::$m:ident) => {
40        impl<T: $tr<U>, U, A, const F: i8> $tr<U> for Q<T, A, F> {
41            #[inline]
42            fn $m(&mut self, rhs: U) {
43                <T as $tr<U>>::$m(&mut self.inner, rhs)
44            }
45        }
46    };
47}
48forward_sh_assign_op!(ShrAssign::shr_assign);
49forward_sh_assign_op!(ShlAssign::shl_assign);
50
51/// ```
52/// # use dsp_fixedpoint::Q8;
53/// assert_eq!(
54///     Q8::<3>::from_f32(3.5) + Q8::from_f32(5.2),
55///     Q8::from_f32(8.7)
56/// );
57/// assert_eq!(
58///     Q8::<3>::from_f32(4.0) - Q8::from_f32(3.2),
59///     Q8::from_f32(0.8)
60/// );
61/// assert_eq!(Q8::<3>::from_f32(3.5) % Q8::from_int(1), Q8::from_f32(0.5));
62/// ```
63macro_rules! forward_binop {
64    ($tr:ident::$m:ident) => {
65        impl<T: $tr<T, Output = T>, A, const F: i8> $tr for Q<T, A, F> {
66            type Output = Self;
67            #[inline]
68            fn $m(self, rhs: Self) -> Self::Output {
69                Self::new(<T as $tr>::$m(self.inner, rhs.inner))
70            }
71        }
72    };
73}
74forward_binop!(Rem::rem);
75forward_binop!(Add::add);
76forward_binop!(Sub::sub);
77forward_binop!(BitAnd::bitand);
78forward_binop!(BitOr::bitor);
79forward_binop!(BitXor::bitxor);
80
81// Mixed Q/integer multiplication deliberately uses operand order to choose
82// between widened and quantized results. See the crate docs for the full table.
83
84/// Wide multiplication to accumulator
85///
86/// ```
87/// # use dsp_fixedpoint::{Q, Q8};
88/// assert_eq!(Q8::<3>::from_bits(4) * 2, Q::from_bits(8));
89/// assert_eq!(Q8::<3>::from_bits(4) / 2, Q8::from_bits(2));
90/// ```
91impl<T: Accu<A>, A: Mul<Output = A>, const F: i8> Mul<T> for Q<T, A, F> {
92    type Output = Q<A, T, F>;
93    #[inline]
94    fn mul(self, rhs: T) -> Q<A, T, F> {
95        self.mul_wide(rhs)
96    }
97}
98
99impl<T: Div<Output = T>, A, const F: i8> Div<T> for Q<T, A, F> {
100    type Output = Self;
101    #[inline]
102    fn div(self, rhs: T) -> Self {
103        Q::new(self.inner / rhs)
104    }
105}
106
107macro_rules! forward_assign_op_foreign {
108    ($tr:ident::$m:ident) => {
109        impl<T: $tr<T>, A, const F: i8> $tr<T> for Q<T, A, F> {
110            #[inline]
111            fn $m(&mut self, rhs: T) {
112                <T as $tr>::$m(&mut self.inner, rhs)
113            }
114        }
115    };
116}
117forward_assign_op_foreign!(MulAssign::mul_assign);
118forward_assign_op_foreign!(DivAssign::div_assign);
119
120macro_rules! forward_assign_op {
121    ($tr:ident::$m:ident) => {
122        impl<T: $tr<T>, A, const F: i8> $tr for Q<T, A, F> {
123            #[inline]
124            fn $m(&mut self, rhs: Self) {
125                <T as $tr>::$m(&mut self.inner, rhs.inner)
126            }
127        }
128    };
129}
130forward_assign_op!(RemAssign::rem_assign);
131forward_assign_op!(AddAssign::add_assign);
132forward_assign_op!(SubAssign::sub_assign);
133forward_assign_op!(BitAndAssign::bitand_assign);
134forward_assign_op!(BitOrAssign::bitor_assign);
135forward_assign_op!(BitXorAssign::bitxor_assign);
136
137/// Q *= Q'
138///
139/// ```
140/// # use dsp_fixedpoint::Q8;
141/// let mut q = Q8::<4>::from_f32(0.25);
142/// q *= Q8::<3>::from_int(3);
143/// assert_eq!(q, Q8::from_f32(0.75));
144/// ```
145impl<T: Copy + Accu<A>, A: Shift + Mul<A, Output = A>, const F: i8, const F1: i8>
146    MulAssign<Q<T, A, F1>> for Q<T, A, F>
147{
148    #[inline]
149    fn mul_assign(&mut self, rhs: Q<T, A, F1>) {
150        let shift = const { -F1 };
151        self.inner = T::down((self.inner.up() * rhs.inner.up()).shs(shift));
152    }
153}
154
155/// Q /= Q'
156///
157/// ```
158/// # use dsp_fixedpoint::Q8;
159/// let mut q = Q8::<4>::from_f32(0.75);
160/// q /= Q8::<3>::from_int(3);
161/// assert_eq!(q, Q8::from_f32(0.25));
162/// ```
163impl<
164    T: Copy + Shift + Accu<A> + Div<T, Output = T>,
165    A: Shift + Div<A, Output = A>,
166    const F: i8,
167    const F1: i8,
168> DivAssign<Q<T, A, F1>> for Q<T, A, F>
169{
170    #[inline]
171    fn div_assign(&mut self, rhs: Q<T, A, F1>) {
172        self.inner = if F1 > 0 {
173            T::down(self.inner.up().shs(F1) / rhs.inner.up())
174        } else {
175            self.inner.shs(F1) / rhs.inner
176        };
177    }
178}
179
180/// Q*Q -> Q
181///
182/// ```
183/// # use dsp_fixedpoint::Q8;
184/// assert_eq!(
185///     Q8::<4>::from_f32(0.75) * Q8::from_int(3),
186///     Q8::from_f32(2.25)
187/// );
188/// ```
189impl<T, A, const F: i8> Mul for Q<T, A, F>
190where
191    Self: MulAssign,
192{
193    type Output = Self;
194    #[inline]
195    fn mul(mut self, rhs: Self) -> Self::Output {
196        self *= rhs;
197        self
198    }
199}
200
201/// Q/Q -> Q
202///
203/// ```
204/// # use dsp_fixedpoint::Q8;
205/// assert_eq!(Q8::<4>::from_int(3) / Q8::from_int(2), Q8::from_f32(1.5));
206/// ```
207impl<T, A, const F: i8> Div for Q<T, A, F>
208where
209    Self: DivAssign,
210{
211    type Output = Self;
212    #[inline]
213    fn div(mut self, rhs: Self) -> Self::Output {
214        self /= rhs;
215        self
216    }
217}
218
219impl<T: iter::Sum, A, const F: i8> iter::Sum for Q<T, A, F> {
220    #[inline]
221    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
222        Self::new(iter.map(|i| i.inner).sum())
223    }
224}