Skip to main content

ohsl/complex/
mod.rs

1pub mod elementary;
2pub mod trigonometric;
3pub mod hyperbolic;
4
5use core::ops::{Add, Div, Mul, Neg, Sub};
6use core::ops::{AddAssign, SubAssign, MulAssign, DivAssign};
7use std::{fmt, cmp::Ordering};
8
9pub use crate::traits::{Number, Signed, Zero, One, Tiny};
10
11pub struct Complex<T> {
12    /// Real part of the complex number
13    pub real: T,
14    /// Imaginary part of the complex number
15    pub imag: T,
16}
17
18pub type Cmplx = Complex<f64>;
19
20impl<T> Complex<T> {
21    /// Create a new complex number ( z = x + iy )
22    #[inline]
23    pub const fn new(real: T, imag: T) -> Self {
24        Complex { real, imag }
25    }
26}
27
28impl<T: Clone + Signed> Complex<T> {
29    /// Return the complex conjugate ( z.conj() = x - iy )
30    #[inline]
31    pub fn conj(&self) -> Self {
32        Self::new(self.real.clone(), -self.imag.clone())
33    }
34}
35
36impl<T: Clone> Clone for Complex<T> {
37    /// Clone the complex number
38    #[inline]
39    fn clone(&self) -> Self {
40        Self::new(self.real.clone(), self.imag.clone())
41    }
42}
43
44impl<T: Clone + Signed> Neg for Complex<T> {
45    type Output = Self;
46    /// Return the unary negation ( unary - )
47    /// - ( a + ib ) = -a - ib
48    #[inline]
49    fn neg(self) -> Self::Output {
50        Self::Output::new( -self.real, -self.imag )
51    }
52}
53
54impl<T: Clone + Number> Add<Complex<T>> for Complex<T> {
55    type Output = Self;
56    /// Add two complex numbers together ( binary + )
57    /// ( a + ib ) + ( c + id ) = ( a + c ) + i( b + d )
58    #[inline]
59    fn add(self, plus: Self) -> Self::Output {
60        Self::Output::new(self.real + plus.real, self.imag + plus.imag)
61    }
62}
63
64impl<T: Clone + Number> Sub<Complex<T>> for Complex<T> {
65    type Output = Self;
66    /// Subtract one complex number from another ( binary - )
67    /// ( a + ib ) - ( c + id ) = ( a - c ) + i( b - d )
68    #[inline]
69    fn sub(self, minus: Self) -> Self::Output {
70        Self::Output::new(self.real - minus.real, self.imag - minus.imag)
71    }
72}
73
74impl<T: Clone + Number> Mul<Complex<T>> for Complex<T> {
75    type Output = Self;
76    /// Multiply two complex numbers together ( binary * )
77    /// ( a + ib ) * ( c + id ) = ( ac - bd ) + i( ad + bc )
78    #[inline]
79    fn mul(self, times: Self) -> Self::Output {
80        let real = self.real.clone() * times.real.clone() - self.imag.clone() * times.imag.clone();  
81        let imag = self.real * times.imag + self.imag * times.real;
82        Self::Output::new( real, imag )
83    }
84}
85
86impl<T: Clone + Number> Div<Complex<T>> for Complex<T> {
87    type Output = Self;
88    /// Divide one complex number by another ( binary / )
89    /// ( a + ib ) / ( c + id ) = [( ac + bd ) + i( bc - ad )] / ( c^2 + d^2 )
90    #[inline]
91    fn div(self, divisor: Self) -> Self::Output {
92        let denominator = divisor.real.clone() * divisor.real.clone() + divisor.imag.clone() * divisor.imag.clone();
93        let real = self.real.clone() * divisor.real.clone() + self.imag.clone() * divisor.imag.clone();  
94        let imag = self.imag * divisor.real - self.real * divisor.imag;
95        Self::Output::new( real / denominator.clone(), imag / denominator )
96    }
97}
98
99impl<T: Number> Add<T> for Complex<T> {
100    type Output = Complex<T>;
101    /// Add a complex number to a real number 
102    /// ( a + ib ) + c = ( a + c ) + ib 
103    fn add(self, plus: T) -> Self::Output {
104        Self::Output::new( self.real + plus, self.imag )
105    }
106}
107
108impl<T: Number> Sub<T> for Complex<T> {
109    type Output = Complex<T>;
110    /// Subtract a real number from a complex number 
111    /// ( a + ib ) - c = ( a - c ) + ib 
112    fn sub(self, minus: T) -> Self::Output {
113        Self::Output::new( self.real - minus, self.imag )
114    }
115}
116
117impl<T: Clone + Number> Mul<T> for Complex<T>  {
118    type Output = Complex<T>;
119    /// Multiply a complex number by a real scalar 
120    /// ( a + ib ) * r = (a*r) + i(b*r) 
121    fn mul(self, scalar: T) -> Self::Output {
122        Self::Output::new( self.real * scalar.clone(), self.imag * scalar )
123    }
124}
125
126impl Mul<Complex<f64>> for f64 {
127    type Output = Complex<f64>;
128    /// Allow multiplication on the left by f64 (f64 * complex number)
129    #[inline]
130    fn mul(self, complex: Complex<f64>) -> Self::Output {
131        complex * self
132    }
133}
134
135impl<T: Clone + Number> Div<T> for Complex<T> {
136    type Output = Complex<T>;
137    /// Divide a complex number by a real scalar 
138    /// ( a + ib ) / r = (a/r) + i(b/r) 
139    fn div(self, scalar: T) -> Self::Output {
140        Self::Output::new( self.real / scalar.clone(), self.imag / scalar )
141    }
142}
143
144impl<T: Number> AddAssign for Complex<T> {
145    /// Add a complex number to a mutable complex variable and assign the
146    /// result to that variable ( += )
147    fn add_assign(&mut self, rhs: Self) {
148        self.real += rhs.real;
149        self.imag += rhs.imag;
150    }
151}
152
153impl<T: Number> SubAssign for Complex<T> {
154    /// Subtract a complex number from a mutable complex variable and assign the
155    /// result to that variable ( -= )
156    fn sub_assign(&mut self, rhs: Self) {
157        self.real -= rhs.real;
158        self.imag -= rhs.imag;
159    }
160}
161
162impl<T: Clone + Number> MulAssign for Complex<T> {
163    /// Multipy a mutable complex variable by a complex number and assign the
164    /// result to that variable ( *= )
165    fn mul_assign(&mut self, rhs: Self) {
166        let a = self.real.clone();
167
168        self.real *= rhs.real.clone();
169        self.real -= self.imag.clone() * rhs.imag.clone();
170
171        self.imag *= rhs.real;
172        self.imag += a * rhs.imag;
173    }
174}
175
176impl<T: Clone + Number> DivAssign for Complex<T> {
177    /// Divide a mutable complex variable by a complex number and assign the
178    /// result to that variable ( *= )
179    fn div_assign(&mut self, rhs: Self) {
180        let a = self.real.clone();
181        let denominator = rhs.real.clone() * rhs.real.clone() + rhs.imag.clone() * rhs.imag.clone();
182        
183        self.real *= rhs.real.clone();
184        self.real += self.imag.clone() * rhs.imag.clone();
185        self.real /= denominator.clone();
186
187        self.imag *= rhs.real;
188        self.imag -= a * rhs.imag;
189        self.imag /= denominator;
190    }
191}
192
193impl<T: Number> AddAssign<T> for Complex<T> {
194    /// Add a real number to a mutable complex variable and assign the
195    /// result to that variable ( += )
196    fn add_assign(&mut self, rhs: T) {
197        self.real += rhs;
198    }
199}
200
201impl<T: Number> SubAssign<T> for Complex<T> {
202    /// Subtract a real number from a mutable complex variable and assign the
203    /// result to that variable ( += )
204    fn sub_assign(&mut self, rhs: T) {
205        self.real -= rhs;
206    }
207}
208
209impl<T: Clone + Number> MulAssign<T> for Complex<T> {
210    /// Multiply a mutable complex variable by a real number and assign the
211    /// result to that variable ( *= )
212    fn mul_assign(&mut self, rhs: T) {
213        self.real *= rhs.clone();
214        self.imag *= rhs;
215    }
216}
217
218impl<T: Clone + Number> DivAssign<T> for Complex<T> {
219    /// Divide a mutable complex variable by a real number and assign the
220    /// result to that variable ( /= )
221    fn div_assign(&mut self, rhs: T) {
222        self.real /= rhs.clone();
223        self.imag /= rhs;
224    }
225}
226
227impl<T: Clone + Number> Zero for Complex<T> {
228    /// Return the additive identity z = 0 + 0i
229    fn zero() -> Self {
230        Self::new(Zero::zero(), Zero::zero())
231    }
232}
233
234impl<T: Clone + Number> One for Complex<T> {
235    /// Return the multiplicative identity z = 1 + 0i
236    fn one() -> Self {
237        Self::new(One::one(), Zero::zero())
238    }
239}
240
241impl<T: Clone + Number> Tiny for Complex<T> {
242    /// Return a very small complex number z = tiny + tiny*i
243    fn tiny() -> Self {
244        Self::new(T::tiny(), T::tiny())
245    }
246}
247
248impl<T: Clone + Number> PartialEq for Complex<T> {
249    /// Implement trait for equality 
250    fn eq(&self, other: &Complex<T>) -> bool {
251        self.real == other.real && self.imag == other.imag
252    }
253}
254
255impl<T: Clone + Number + std::cmp::PartialOrd> PartialOrd for Complex<T> {
256    /// Implement trait for ordering 
257    fn partial_cmp(&self, other: &Complex<T>) -> Option<Ordering> {
258        if self.real != other.real {
259            self.real.partial_cmp( &other.real )
260        } else {
261            self.imag.partial_cmp( &other.imag )
262        }
263    }
264}
265
266impl<T: Clone + Number> Complex<T> {
267    /// Return the absolute value squared ( |z|^2 = z * z.conj() )
268    #[inline]
269    pub fn abs_sqr(&self) -> T {
270        self.real.clone() * self.real.clone() + self.imag.clone() * self.imag.clone()
271    }
272}
273
274impl Complex::<f64> {
275    /// Return the absolute value ( |z| = sqrt( z * z.conj() ) )
276    #[inline]
277    pub fn abs(&self) -> f64 {
278        f64::sqrt( self.abs_sqr() )
279    }
280}
281
282impl Complex::<f64> {
283    /// Return the phase angle in radians
284    #[inline]
285    pub fn arg(&self) -> f64 {
286        self.imag.atan2(self.real)
287    }
288}
289
290impl<T> fmt::Display for Complex<T> where
291    T: fmt::Display
292{
293    /// Format the output ( z = x + iy = ( x, y ) )
294    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295        write!(f, "( {}, {} )", self.real, self.imag )
296    }
297} 
298
299impl<T> fmt::Debug for Complex<T> where
300    T: fmt::Debug
301{
302    /// Format the output ( z = x + iy = ( x, y ) )
303    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304        write!(f, "( {:?}, {:?} )", self.real, self.imag )
305    }
306} 
307
308impl<T: Number + Clone> Number for Complex<T> {
309
310}
311
312impl Signed for Complex<f64> {
313    fn abs(&self) -> Self {
314        //let real = self.abs();
315        let real: f64 = self.abs();
316        let imag: f64 = 0.0;
317        Complex { real, imag }
318    }
319}
320
321impl Copy for Complex<f64> {
322
323}