number_complex/
lib.rs

1use std::{ops::{Add, Sub, Mul, Div}, fmt::{Display, Debug}, f64::consts::PI};
2
3pub trait Complex: Add + Sub + Mul + Div + Display + Debug + Sized {
4    fn conjugate(&self) -> Self;
5}
6
7 #[derive(Debug)]
8pub struct Rectangular {
9    real: f64,
10    imag: f64,
11}
12
13impl Rectangular {
14    pub fn new(real: f64, imag: f64) -> Self {
15        Self { real, imag }
16    }
17
18    pub fn get_polar(&self) -> Polar {
19        let modulus = (self.real.powf(2.) + self.imag.powf(2.)).sqrt();
20        let mut arg = (self.real/self.imag).atan();
21
22
23        if self.real.is_sign_negative() && self.imag.is_sign_negative() {
24            // arctan registers in first quadrant but we're actually in third
25            arg += PI;
26        } else if self.real.is_sign_positive() && self.imag.is_sign_negative() {
27            // arctan registers in fourth quadrant but we're actually in second
28            arg += PI
29        } else if arg.is_sign_negative() {
30            arg += 2.*PI;
31        }
32
33        Polar::new(arg, modulus)
34    }
35
36    pub fn real(&self) -> f64 {
37        self.real
38    }
39
40    pub fn imag(&self) -> f64 {
41        self.imag
42    }
43}
44
45impl Complex for Rectangular {
46    fn conjugate(&self) -> Self {
47        Self { real: self.real, imag: -self.imag }
48    }
49}
50
51impl Add for Rectangular {
52    type Output = Self;
53    fn add(self, rhs: Self) -> Self::Output {
54        let real = self.real + rhs.real;
55        let imag = self.imag + rhs.imag;
56        Self { real, imag }
57    }
58}
59
60impl Add<f64> for Rectangular {
61    type Output = Self;
62    fn add(self, rhs: f64) -> Self::Output {
63        let real = self.real + rhs;
64        Self { real, imag: self.imag }
65    }
66}
67
68impl Sub for Rectangular {
69    type Output = Self;
70    fn sub(self, rhs: Self) -> Self::Output {
71        let real = self.real - rhs.real;
72        let imag = self.imag - rhs.imag;
73        Self { real, imag }
74    }
75}
76
77impl Sub<f64> for Rectangular {
78    type Output = Self;
79    fn sub(self, rhs: f64) -> Self::Output {
80        let real = self.real - rhs;
81        Self { real, imag: self.imag }
82    }
83}
84
85// we're going to have four terms, two of which are real and two of which are imaginary
86// (a +bi)(c+ di) = ac + cbi + adi - bd
87impl Mul for Rectangular {
88    type Output = Self;
89    fn mul(self, rhs: Self) -> Self::Output {
90        let real = self.real * rhs.real - self.imag * rhs.imag;
91        let imag = self.imag * rhs.real + self.real * rhs.imag;
92        Self { real, imag }
93    }
94}
95
96impl Mul<f64> for Rectangular {
97    type Output = Self;
98    fn mul(self, rhs: f64) -> Self::Output {
99        let real = self.real * rhs;
100        let imag = self.imag * rhs;
101        Self { real, imag }
102    }
103}
104
105// note that (a+bi)/(c+di) = (a+bi)(b-di)/(c^2 + d^2)
106impl Div for Rectangular {
107    type Output = Self;
108    fn div(self, rhs: Self) -> Self::Output {
109        let numerator = self * Self { real: rhs.real, imag: -rhs.imag };
110        let denomenator = rhs.real.powf(2.) + rhs.imag.powf(2.);
111        let real = numerator.real / denomenator;
112        let imag = numerator.imag / denomenator;
113
114        Self { real, imag }
115    }
116    
117}
118
119impl Div<f64> for Rectangular {
120    type Output = Self;
121    fn div(self, rhs: f64) -> Self::Output {
122        let real = self.real / rhs;
123        let imag = self.real / rhs;
124        Self { real, imag }
125    }
126}
127
128impl Display for Rectangular {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        write!(f, "{} + {}i", self.real, self.imag)
131    }
132    
133}
134
135#[derive(Debug)]
136pub struct Polar {
137    arg: f64,
138    modulus: f64,
139}
140
141impl Polar {
142    pub fn new(arg: f64, modulus: f64) -> Self {
143        Self { arg, modulus }
144    }
145
146    pub fn get_rectangular(&self) -> Rectangular {
147        let real = self.modulus * self.arg.cos();
148        let imag = self.modulus * self.arg.sin();
149        Rectangular::new(real, imag)
150    }
151
152    pub fn arg(&self) -> f64 {
153        self.arg
154    }
155
156    pub fn modulus(&self) -> f64 {
157        self.modulus
158    }
159}
160
161impl Complex for Polar {
162    fn conjugate(&self) -> Self {
163        Self { arg: 2.*PI - self.arg, modulus: self.modulus }
164    }
165}
166
167impl Add for Polar {
168    type Output = Self;
169
170    fn add(self, rhs: Self) -> Self::Output {
171        let rect_self = self.get_rectangular();
172        let rect_rhs = rhs.get_rectangular();
173
174        (rect_self + rect_rhs).get_polar()
175    }
176}
177
178impl Sub for Polar {
179    type Output = Self;
180    fn sub(self, rhs: Self) -> Self::Output {
181        let rect_self = self.get_rectangular();
182        let rect_rhs = rhs.get_rectangular();
183
184        (rect_self - rect_rhs).get_polar()
185    }
186}
187
188impl Mul for Polar {
189    type Output = Self;
190    fn mul(self, rhs: Self) -> Self::Output {
191        let modulus = self.modulus * rhs.modulus;
192        let mut arg = self.arg + rhs.arg;
193
194        if arg > 2.*PI {
195            arg -= 2.* PI;
196        }
197
198        Self { arg, modulus }
199    }
200}
201
202impl Div for Polar {
203    type Output = Self;
204    fn div(self, rhs: Self) -> Self::Output {
205        let modulus = self.modulus / rhs.modulus;
206        let mut arg = self.arg - rhs.arg;
207
208        if arg < 0. {
209            arg += 2.*PI;
210        }
211
212        Self { arg, modulus }
213    }
214}
215
216impl Display for Polar {
217    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218        write!(f, "{}*e^{}i", self.modulus, self.arg)
219    }
220}