swnb_complex/
lib.rs

1use std::{
2    fmt::{Debug, Write},
3    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
4};
5
6#[derive(Clone, Copy, Eq, PartialEq)]
7pub struct Complex<T: Copy> {
8    real: T,
9    imaginary: T,
10}
11
12impl<T> Debug for Complex<T>
13where
14    T: Debug + Copy,
15{
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        f.write_char('(')?;
18        self.real.fmt(f)?;
19        f.write_str(", ")?;
20        self.imaginary.fmt(f)?;
21        f.write_char('i')?;
22        f.write_char(')')?;
23        Ok(())
24    }
25}
26
27#[macro_export]
28macro_rules! c {
29    ($real:tt +i $imaginary:tt) => {
30        Complex::new($real, $imaginary)
31    };
32    ($real:tt -i $imaginary:tt) => {
33        Complex::new($real, -($imaginary))
34    };
35    (-$real:tt +i $imaginary:tt) => {
36        Complex::new(-$real, $imaginary)
37    };
38    (-$real:tt -i $imaginary:tt) => {
39        Complex::new(-$real, -($imaginary))
40    };
41}
42
43impl<T> Complex<T>
44where
45    T: Copy,
46{
47    #[inline]
48    pub fn new(r: T, i: T) -> Self {
49        Self {
50            real: r,
51            imaginary: i,
52        }
53    }
54
55    #[inline]
56    pub fn real(&self) -> T {
57        self.real
58    }
59
60    #[inline]
61    pub fn imaginary(&self) -> T {
62        self.imaginary
63    }
64
65    #[inline]
66    pub fn set_real(&mut self, real: T) {
67        self.real = real
68    }
69
70    #[inline]
71    pub fn set_imaginary(&mut self, imaginary: T) {
72        self.imaginary = imaginary
73    }
74}
75
76impl<T> Add<Complex<T>> for Complex<T>
77where
78    T: Add<Output = T> + Copy,
79{
80    type Output = Self;
81
82    fn add(self, rhs: Complex<T>) -> Self::Output {
83        (self.real + rhs.real, self.imaginary + rhs.imaginary).into()
84    }
85}
86
87impl<T> Add<T> for Complex<T>
88where
89    T: Add<Output = T> + Copy,
90{
91    type Output = Self;
92
93    fn add(self, rhs: T) -> Self::Output {
94        (self.real + rhs, self.imaginary).into()
95    }
96}
97
98impl<T> AddAssign<Complex<T>> for Complex<T>
99where
100    T: AddAssign + Copy,
101{
102    fn add_assign(&mut self, rhs: Complex<T>) {
103        self.real += rhs.real;
104        self.imaginary += rhs.imaginary;
105    }
106}
107
108impl<T> AddAssign<T> for Complex<T>
109where
110    T: AddAssign + Copy,
111{
112    fn add_assign(&mut self, rhs: T) {
113        self.real += rhs;
114    }
115}
116
117impl<T> Sub<Complex<T>> for Complex<T>
118where
119    T: Sub<Output = T> + Copy,
120{
121    type Output = Self;
122
123    fn sub(self, rhs: Complex<T>) -> Self::Output {
124        (self.real - rhs.real, self.imaginary - rhs.imaginary).into()
125    }
126}
127
128impl<T> Sub<T> for Complex<T>
129where
130    T: Sub<Output = T> + Copy,
131{
132    type Output = Self;
133
134    fn sub(self, rhs: T) -> Self::Output {
135        (self.real - rhs, self.imaginary).into()
136    }
137}
138
139impl<T> SubAssign<Complex<T>> for Complex<T>
140where
141    T: SubAssign + Copy,
142{
143    fn sub_assign(&mut self, rhs: Complex<T>) {
144        self.real -= rhs.real;
145        self.imaginary -= rhs.imaginary;
146    }
147}
148
149impl<T> SubAssign<T> for Complex<T>
150where
151    T: SubAssign + Copy,
152{
153    fn sub_assign(&mut self, rhs: T) {
154        self.real -= rhs;
155    }
156}
157
158impl<T> Mul<Complex<T>> for Complex<T>
159where
160    T: Mul<Output = T> + Sub<Output = T> + Add<Output = T> + Copy,
161{
162    type Output = Complex<T>;
163    fn mul(self, rhs: Complex<T>) -> Self::Output {
164        let real: T = self.real * rhs.real - (self.imaginary * rhs.imaginary);
165        let imaginary: T = self.imaginary * rhs.real + (rhs.imaginary * self.real);
166        (real, imaginary).into()
167    }
168}
169
170impl<T> Mul<T> for Complex<T>
171where
172    T: Mul<Output = T> + Sub<Output = T> + Add<Output = T> + Copy,
173{
174    type Output = Complex<T>;
175    fn mul(self, rhs: T) -> Self::Output {
176        let real: T = self.real * rhs;
177        let imaginary: T = self.imaginary * rhs;
178        (real, imaginary).into()
179    }
180}
181
182impl<T> MulAssign<Complex<T>> for Complex<T>
183where
184    T: Mul<Output = T> + Sub<Output = T> + Add<Output = T> + Copy,
185{
186    fn mul_assign(&mut self, rhs: Complex<T>) {
187        let real: T = self.real * rhs.real - (self.imaginary * rhs.imaginary);
188        let imaginary: T = self.imaginary * rhs.real + (rhs.imaginary * self.real);
189        self.real = real;
190        self.imaginary = imaginary;
191    }
192}
193
194impl<T> MulAssign<T> for Complex<T>
195where
196    T: Mul<Output = T> + Sub<Output = T> + Add<Output = T> + Copy,
197{
198    fn mul_assign(&mut self, rhs: T) {
199        let real: T = self.real * rhs;
200        let imaginary: T = self.imaginary * rhs;
201        self.real = real;
202        self.imaginary = imaginary;
203    }
204}
205
206impl<T> Div<Complex<T>> for Complex<T>
207where
208    T: Copy + Mul<Output = T> + Add<Output = T> + Div<Output = T> + Sub<Output = T>,
209{
210    type Output = Self;
211    fn div(self, rhs: Complex<T>) -> Self::Output {
212        // (a+bi)/(c+di)=(ac+bd)/(c^2+d^2) +((bc-ad)/(c^2+d^2))i
213        let a = self.real;
214        let b = self.imaginary;
215        let c = rhs.real;
216        let d = rhs.imaginary;
217
218        let real = ((a * c) + (b * d)) / ((c * c) + (d * d));
219        let imaginary = ((b * c) - (a * d)) / ((c * c) + (d * d));
220        (real, imaginary).into()
221    }
222}
223
224impl<T> Div<T> for Complex<T>
225where
226    T: Copy + Mul<Output = T> + Add<Output = T> + Div<Output = T> + Sub<Output = T>,
227{
228    type Output = Self;
229    fn div(self, rhs: T) -> Self::Output {
230        // (a+bi)/(c+di)=(ac+bd)/(c^2+d^2) +((bc-ad)/(c^2+d^2))i
231        let a = self.real;
232        let b = self.imaginary;
233        let c = rhs;
234
235        let real = a / c;
236        let imaginary = b / c;
237
238        (real, imaginary).into()
239    }
240}
241
242impl<T> DivAssign<Complex<T>> for Complex<T>
243where
244    T: Copy + Mul<Output = T> + Add<Output = T> + Div<Output = T> + Sub<Output = T>,
245{
246    fn div_assign(&mut self, rhs: Complex<T>) {
247        // (a+bi)/(c+di)=(ac+bd)/(c^2+d^2) +((bc-ad)/(c^2+d^2))i
248        let a = self.real;
249        let b = self.imaginary;
250        let c = rhs.real;
251        let d = rhs.imaginary;
252
253        let real = ((a * c) + (b * d)) / ((c * c) + (d * d));
254        let imaginary = ((b * c) - (a * d)) / ((c * c) + (d * d));
255
256        self.real = real;
257        self.imaginary = imaginary;
258    }
259}
260
261impl<T> DivAssign<T> for Complex<T>
262where
263    T: Copy + Mul<Output = T> + Add<Output = T> + Div<Output = T> + Sub<Output = T>,
264{
265    fn div_assign(&mut self, rhs: T) {
266        // (a+bi)/(c+di)=(ac+bd)/(c^2+d^2) +((bc-ad)/(c^2+d^2))i
267        let a = self.real;
268        let b = self.imaginary;
269        let c = rhs;
270
271        let real = a / c;
272        let imaginary = b / c;
273
274        self.real = real;
275        self.imaginary = imaginary;
276    }
277}
278
279impl<T> Neg for Complex<T>
280where
281    T: Neg<Output = T> + Copy,
282{
283    type Output = Self;
284
285    fn neg(self) -> Self::Output {
286        (-self.real, -self.imaginary).into()
287    }
288}
289
290impl<T: Copy> From<(T, T)> for Complex<T> {
291    fn from((r, i): (T, T)) -> Self {
292        Self::new(r, i)
293    }
294}
295
296impl<T> From<T> for Complex<T>
297where
298    T: Copy + Default,
299{
300    fn from(r: T) -> Self {
301        Self::new(r, T::default())
302    }
303}
304
305#[cfg(test)]
306mod tests {
307    use super::*;
308
309    #[test]
310    fn it_works() {
311        // https://mathsolver.microsoft.com/zh/solve-problem/
312
313        let a = c!(3 + i 2);
314        let b = c!(2 - i 3);
315
316        let c = a * b;
317        assert_eq!(c, (12, -9 + 4).into());
318
319        let c = a + b;
320        assert_eq!(c, c!(5 - i 1));
321
322        let c = a - b;
323        assert_eq!(c, c!(1 + i 5));
324
325        assert_eq!(b - a, -c);
326
327        assert_eq!(a / b, (0, 1).into());
328    }
329}