complex_stuff/
lib.rs

1//! `complex-stuff` is a collection of utilities to make calculations with complex numbers easy.
2//!
3//! # Examples
4//!
5//! ```
6//! use complex_stuff::{Complex, ComplexCartesian, ComplexPolar};
7//! use std::f64::consts::PI;
8//!
9//! // Some of the most important operations:
10//! fn main() {
11//!     // Declare complex numbers with their cartesian or polar form.
12//!     let c1 = Complex::new_cartesian(5.0, 3.0);
13//!     let c2 = Complex::new_polar(7.0, PI / 4.0);
14//!
15//!     // Basic arethmetic operations should work as expected.
16//!     let sum = c1 + c2;
17//!     let diff = c1 - c2;
18//!
19//!     let prod = c1 * c2;
20//!
21//!     // All operations which can result in undefined or infinite values
22//!     // return a `Option` and need to be handled.
23//!
24//!     let quot = (c1 / c2)?;
25//!
26//!     let sqr = c1.pow(Complex::new_real(2.0))?;
27//!     let sqrt = c1.root(Complex::new_real(2.0))?;
28//!
29//!     let log10 = c1.log(Complex::new_real(10.0))?;
30//!     
31//!     let sin = c1.sin()?;
32//!     let cos = c1.cos()?;
33//! }
34//! ```
35
36use std::{
37    f64::consts::E,
38    ops::{Add, Div, Mul, Neg, Sub},
39};
40
41#[derive(Debug, Clone, Copy)]
42/// Descibes a complex number in cartesion form _`re` + `im`i_.
43pub struct ComplexCartesian {
44    pub re: f64,
45    pub im: f64,
46}
47
48impl std::fmt::Display for ComplexCartesian {
49    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
50        write!(f, "{} + {}i", self.re, self.im)
51    }
52}
53
54impl ComplexCartesian {
55    /// Converts a complex number from polar to cartesion form.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use std::f64::consts::PI;
61    /// use complex_stuff::{ComplexCartesian, ComplexPolar};
62    ///
63    /// let polar = ComplexPolar { mag: 5.0, ang: PI / 2.0 };
64    /// let cartesian = ComplexCartesian::from_polar(&polar);
65    /// ```
66    pub fn from_polar(polar: &ComplexPolar) -> Self {
67        let re = polar.mag * polar.ang.cos();
68        let im = polar.mag * polar.ang.sin();
69        return Self { re, im };
70    }
71}
72
73#[derive(Debug, Clone, Copy)]
74/// Describes a complex number in polar form _`mag`e^(`ang`i)_
75pub struct ComplexPolar {
76    pub mag: f64,
77    pub ang: f64,
78}
79
80impl std::fmt::Display for ComplexPolar {
81    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
82        write!(f, "{}e^({}i)", self.mag, self.ang)
83    }
84}
85
86impl ComplexPolar {
87    /// Converts a complex number from cartesian to polar form.
88    ///
89    /// # Examples
90    ///
91    /// ```
92    /// use complex_stuff::{ComplexCartesian, ComplexPolar};
93    ///
94    /// let cartesian = ComplexCartesian { re: 5.0, im: 3.0 };
95    /// let polar = ComplexPolar::from_cartesian(&cartesian);
96    /// ```
97    pub fn from_cartesian(cartesian: &ComplexCartesian) -> Self {
98        let mag = (cartesian.re * cartesian.re + cartesian.im * cartesian.im).sqrt();
99        let ang = (cartesian.re / mag).acos();
100        return Self { mag, ang };
101    }
102}
103
104#[derive(Debug, Clone, Copy)]
105/// Describes a complex number in both cartesian and polar form.
106pub struct Complex {
107    cartesian: ComplexCartesian,
108    polar: ComplexPolar,
109}
110
111impl std::fmt::Display for Complex {
112    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
113        write!(f, "Cartesian: {}\nPolar: {}", self.cartesian, self.polar)
114    }
115}
116
117impl Complex {
118    /// Creates a complex number from its cartesian parts.
119    ///
120    /// # Examples
121    ///
122    /// ```
123    /// use complex_stuff::Complex;
124    ///
125    /// let complex = Complex::new_cartesian(5.0, 3.0);
126    /// ```
127    pub fn new_cartesian(re: f64, im: f64) -> Self {
128        let cartesian = ComplexCartesian { re, im };
129        let polar = ComplexPolar::from_cartesian(&cartesian);
130
131        Self { cartesian, polar }
132    }
133
134    /// Creates a complex number from its polar parts.
135    ///
136    /// # Examples
137    ///
138    /// ```
139    /// use std::f64::consts::PI;
140    /// use complex_stuff::Complex;
141    ///
142    /// let complex = Complex::new_polar(5.0, PI / 2.0);
143    /// ```
144    pub fn new_polar(mag: f64, ang: f64) -> Self {
145        let polar = ComplexPolar { mag, ang };
146        let cartesian = ComplexCartesian::from_polar(&polar);
147
148        Self { cartesian, polar }
149    }
150
151    /// Creates a complex number just from its real cartesian part leaving the imaginary part 0.
152    ///
153    /// # Examples
154    ///
155    /// ```
156    /// use complex_stuff::Complex;
157    ///
158    /// let complex = Complex::new_real(5.0);
159    ///
160    /// assert_eq!(5.0, complex.re());
161    /// assert_eq!(0.0, complex.im());
162    /// ```
163    pub fn new_real(re: f64) -> Self {
164        Self::new_cartesian(re, 0.0)
165    }
166
167    /// Creates a complex number just from its imaginary cartesian part leaving the real part 0.
168    ///
169    /// # Examples
170    ///
171    /// ```
172    /// use complex_stuff::Complex;
173    ///
174    /// let complex = Complex::new_imaginary(3.0);
175    ///
176    /// assert_eq!(0.0, complex.re());
177    /// assert_eq!(3.0, complex.im());
178    /// ```
179    pub fn new_imaginary(im: f64) -> Self {
180        Self::new_cartesian(0.0, im)
181    }
182
183    /// Creates a complex number representing the value 0.
184    ///
185    /// # Examples
186    ///
187    /// ```
188    /// use complex_stuff::Complex;
189    ///
190    /// let complex = Complex::zero();
191    ///
192    /// assert_eq!(0.0, complex.re());
193    /// assert_eq!(0.0, complex.im());
194    /// ```
195    pub fn zero() -> Self {
196        Self::new_cartesian(0.0, 0.0)
197    }
198
199    /// Creates a complex number representing the value 1.
200    ///
201    /// # Examples
202    ///
203    /// ```
204    /// use complex_stuff::Complex;
205    ///
206    /// let complex = Complex::one();
207    ///
208    /// assert_eq!(1.0, complex.re());
209    /// assert_eq!(0.0, complex.im());
210    /// ```
211    pub fn one() -> Self {
212        Self::new_cartesian(1.0, 0.0)
213    }
214
215    /// Creates a complex number representing the value i.
216    ///
217    /// # Examples
218    ///
219    /// ```
220    /// use complex_stuff::Complex;
221    ///
222    /// let complex = Complex::i();
223    ///
224    /// assert_eq!(0.0, complex.re());
225    /// assert_eq!(1.0, complex.im());
226    /// ```
227    pub fn i() -> Self {
228        Self::new_cartesian(0.0, 1.0)
229    }
230
231    /// Creates a complex number representing the value e.
232    ///
233    /// # Examples
234    ///
235    /// ```
236    /// use std::f64::consts::E;
237    /// use complex_stuff::Complex;
238    ///
239    /// let complex = Complex::e();
240    ///
241    /// assert_eq!(E, complex.re());
242    /// assert_eq!(0.0, complex.im());
243    /// ```
244    pub fn e() -> Self {
245        Self::new_real(E)
246    }
247}
248
249impl Complex {
250    /// Returns the complex number in cartesian form.
251    ///
252    /// # Examples
253    ///
254    /// ```
255    /// use complex_stuff::Complex;
256    ///
257    /// let complex = Complex::new_cartesian(5.0, 3.0);
258    ///
259    /// let cartesian = complex.cartesian();
260    ///
261    /// assert_eq!(5.0, cartesian.re);
262    /// assert_eq!(3.0, cartesian.im);
263    /// ```
264    pub fn cartesian(&self) -> ComplexCartesian {
265        self.cartesian
266    }
267
268    /// Returns the complex number in polar form.
269    ///
270    /// # Examples
271    ///
272    /// ```
273    /// use std::f64::consts::PI;
274    /// use complex_stuff::Complex;
275    ///
276    /// let complex = Complex::new_polar(5.0, PI / 2.0);
277    ///
278    /// let polar = complex.polar();
279    ///
280    /// assert_eq!(5.0, polar.mag);
281    /// assert_eq!(PI / 2.0, polar.ang);
282    /// ```
283    pub fn polar(&self) -> ComplexPolar {
284        self.polar
285    }
286
287    /// Returns just the real part of the complex numbers cartesian form.
288    ///
289    /// # Examples
290    ///
291    /// ```
292    /// use complex_stuff::Complex;
293    ///
294    /// let complex = Complex::new_cartesian(5.0, 3.0);
295    ///
296    /// let real = complex.re();
297    ///
298    /// assert_eq!(5.0, real);
299    /// ```
300    pub fn re(&self) -> f64 {
301        self.cartesian.re
302    }
303
304    /// # Examples
305    ///
306    /// ```
307    /// use complex_stuff::Complex;
308    ///
309    /// let complex = Complex::new_cartesian(5.0, 3.0);
310    ///
311    /// let imaginary = complex.im();
312    ///
313    /// assert_eq!(3.0, imaginary);
314    /// ```
315    /// Returns just the imaginary part of the complex numbers cartesian form.
316    pub fn im(&self) -> f64 {
317        self.cartesian.im
318    }
319
320    /// Returns just the magnitude of the complex numbers polar form.
321    ///
322    /// # Examples
323    ///
324    /// ```
325    /// use std::f64::consts::PI;
326    /// use complex_stuff::Complex;
327    ///
328    /// let complex = Complex::new_polar(5.0, PI / 2.0);
329    ///
330    /// let magnitude = complex.mag();
331    ///
332    /// assert_eq!(5.0, magnitude);
333    /// ```
334    pub fn mag(&self) -> f64 {
335        self.polar.mag
336    }
337
338    /// Returns just the angle of the complex numbers polar form.
339    ///
340    /// # Examples
341    ///
342    /// ```
343    /// use std::f64::consts::PI;
344    /// use complex_stuff::Complex;
345    ///
346    /// let complex = Complex::new_polar(5.0, PI / 2.0);
347    ///
348    /// let angle = complex.ang();
349    ///
350    /// assert_eq!(PI / 2.0, angle);
351    /// ```
352    pub fn ang(&self) -> f64 {
353        self.polar.ang
354    }
355}
356
357impl Complex {
358    /// Returns the negation of the complex number.
359    /// Same as using the unary negation operator `-`.
360    ///
361    /// # Examples
362    ///
363    /// ```
364    /// use complex_stuff::Complex;
365    ///
366    /// let complex = Complex::new_cartesian(5.0, 3.0);
367    ///
368    /// let opposite = complex.opposite();
369    ///
370    /// assert_eq!(-5.0, opposite.re());
371    /// assert_eq!(-3.0, opposite.im());
372    /// ```
373    pub fn opposite(self) -> Self {
374        let re = -self.cartesian.re;
375        let im = -self.cartesian.im;
376        Self::new_cartesian(re, im)
377    }
378
379    /// Returns the reciprocal of the complex number.
380    /// # Examples
381    ///
382    /// ```
383    /// use complex_stuff::Complex;
384    ///
385    /// let complex = Complex::new_cartesian(5.0, 0.0);
386    ///
387    /// let reciprocal = complex.reciprocal();
388    /// ```
389    pub fn reciprocal(self) -> Option<Self> {
390        Self::one() / self
391    }
392}
393
394impl Neg for Complex {
395    type Output = Self;
396
397    fn neg(self) -> Self {
398        self.opposite()
399    }
400}
401
402impl Add for Complex {
403    type Output = Self;
404
405    /// Performs the `+` operation.
406    ///
407    /// # Examples
408    ///
409    /// ```
410    /// use complex_stuff::Complex;
411    ///
412    /// let c1 = Complex::new_cartesian(5.0, 3.0);
413    /// let c2 = Complex::new_cartesian(1.0, 2.0);
414    ///
415    /// let sum = c1 + c2;
416    ///
417    /// assert_eq!(6.0, sum.re());
418    /// assert_eq!(5.0, sum.im());
419    /// ```
420    fn add(self, other: Self) -> Self {
421        let re = self.cartesian.re + other.cartesian.re;
422        let im = self.cartesian.im + other.cartesian.im;
423
424        Self::new_cartesian(re, im)
425    }
426}
427
428impl Sub for Complex {
429    type Output = Self;
430
431    /// Performs the `-` operation.
432    ///
433    /// # Examples
434    ///
435    /// ```
436    /// use complex_stuff::Complex;
437    ///
438    /// let c1 = Complex::new_cartesian(5.0, 3.0);
439    /// let c2 = Complex::new_cartesian(1.0, 2.0);
440    ///
441    /// let diff = c1 - c2;
442    ///
443    /// assert_eq!(4.0, diff.re());
444    /// assert_eq!(1.0, diff.im());
445    /// ```
446    fn sub(self, other: Self) -> Self {
447        let re = self.cartesian.re - other.cartesian.re;
448        let im = self.cartesian.im - other.cartesian.im;
449
450        Self::new_cartesian(re, im)
451    }
452}
453
454impl Mul for Complex {
455    type Output = Self;
456
457    /// Performs the `*` operation.
458    ///
459    /// # Examples
460    ///
461    /// ```
462    /// use complex_stuff::Complex;
463    ///
464    /// let c1 = Complex::new_polar(5.0, 2.0);
465    /// let c2 = Complex::new_polar(2.0, 1.0);
466    ///
467    /// let product = c1 * c2;
468    ///
469    /// assert_eq!(10.0, product.mag());
470    /// assert_eq!(3.0, product.ang());
471    /// ```
472    fn mul(self, other: Self) -> Self {
473        let mag = self.polar.mag * other.polar.mag;
474        let ang = self.polar.ang + other.polar.ang;
475
476        Self::new_polar(mag, ang)
477    }
478}
479
480impl Div for Complex {
481    type Output = Option<Self>;
482
483    /// Performs the `/` operation.
484    ///
485    /// Returns `None` when the result is undefined or infinite.
486    ///
487    /// # Examples
488    ///
489    /// ```ignore
490    /// use complex_stuff::Complex;
491    ///
492    /// let c1 = Complex::new_polar(5.0, 2.0);
493    /// let c2 = Complex::new_polar(2.0, 1.0);
494    ///
495    /// let quotient = (c1 / c2)?;
496    ///
497    /// assert_eq!(2.5, product.mag());
498    /// assert_eq!(1.0, product.ang());
499    /// ```
500    fn div(self, other: Self) -> Option<Self> {
501        if other.polar.mag == 0.0 {
502            return None;
503        }
504
505        let mag = self.polar.mag / other.polar.mag;
506        let ang = self.polar.ang - other.polar.ang;
507
508        Some(Self::new_polar(mag, ang))
509    }
510}
511
512impl Complex {
513    /// Returns the natural logarithm of the complex number.
514    ///
515    /// Returns `None` when the result is undefined or infinite.
516    ///
517    /// # Examples
518    ///
519    /// ```ignore
520    /// use complex_stuff::Complex;
521    ///
522    /// let complex = Complex::new_cartesian(5.0, 3.0);
523    ///
524    /// let result = complex.ln()?;
525    /// ```
526    pub fn ln(self) -> Option<Self> {
527        if self.polar.mag == 0.0 {
528            return None;
529        }
530
531        let re = self.polar.mag.ln();
532        let im = self.polar.ang;
533
534        Some(Self::new_cartesian(re, im))
535    }
536
537    /// Returns the logarithm to any other base of the complex number.
538    ///
539    /// Returns `None` when the result is undefined or infinite.
540    ///
541    /// # Examples
542    ///
543    /// ```ignore
544    /// use complex_stuff::Complex;
545    ///
546    /// let complex = Complex::new_cartesian(5.0, 3.0);
547    /// let base = Complex::new_cartesian(7.0, 10.0);
548    ///
549    /// let result = complex.log(base)?;
550    /// ```
551    pub fn log(self, other: Self) -> Option<Self> {
552        if other.polar.mag == 1.0 || self.polar.mag == 0.0 {
553            return None;
554        }
555
556        if other.polar.mag == 0.0 {
557            return Some(Self::zero());
558        }
559
560        let mag_s = self.polar.mag;
561        let ang_s = self.polar.ang;
562
563        let mag_o = other.polar.mag;
564        let ang_o = other.polar.ang;
565
566        let divisor = mag_o.ln().powi(2) + ang_o.powi(2);
567
568        let re = (mag_s.ln() * mag_o.ln() + ang_s * ang_o) / divisor;
569        let im = (ang_s * mag_o.ln() - ang_o * mag_s.ln()) / divisor;
570
571        Some(Self::new_cartesian(re, im))
572    }
573}
574
575impl Complex {
576    /// Raises the complex number to any other complex number and returns the result.
577    ///
578    /// Returns `None` when the result is undefined or infinite.
579    ///
580    /// # Examples
581    ///
582    /// ```ignore
583    /// use complex_stuff::Complex;
584    ///
585    /// let complex = Complex::new_cartesian(5.0, 3.0);
586    /// let exponent = Complex::new_cartesian(2.0, 1.0);
587    ///
588    /// let result = complex.pow(exponent)?;
589    /// ```
590    pub fn pow(self, other: Self) -> Option<Self> {
591        if self.polar.mag == 0.0 && other.polar.mag == 0.0 {
592            return None;
593        }
594
595        if other.polar.mag == 0.0 {
596            return Some(Self::one());
597        }
598
599        if self.polar.mag == 0.0 {
600            return Some(Self::zero());
601        }
602
603        let b_mag = self.polar.mag;
604        let b_ang = self.polar.ang;
605
606        let e_re = other.cartesian.re;
607        let e_im = other.cartesian.im;
608
609        let mag = (e_re * b_mag.ln() - e_im * b_ang).exp();
610        let ang = e_re * b_ang + e_im * b_mag.ln();
611
612        Some(Self::new_polar(mag, ang))
613    }
614
615    /// Retuns the nth root of the complex number with n being any other complex number.
616    ///
617    /// Returns `None` when the result is undefined or infinite.
618    ///
619    /// # Examples
620    ///
621    /// ```ignore
622    /// use complex_stuff::Complex;
623    ///
624    /// let complex = Complex::new_cartesian(5.0, 3.0);
625    /// let n = Complex::new_cartesian(2.0, 1.0);
626    ///
627    /// let result = complex.root(n)?;
628    /// ```
629    pub fn root(self, other: Self) -> Option<Self> {
630        self.pow(other.reciprocal()?)
631    }
632}
633
634impl Complex {
635    /// Returns the sine of the complex number.
636    ///
637    /// Returns `None` when the result is undefined or infinite.
638    ///
639    /// # Examples
640    ///
641    /// ```ignore
642    /// use complex_stuff::Complex;
643    ///
644    /// let complex = Complex::new_cartesian(5.0, 3.0);
645    ///
646    /// let result = complex.sin()?;
647    /// ```
648    pub fn sin(self) -> Option<Self> {
649        let re = self.cartesian.re.sin() * self.cartesian.im.cosh();
650        let im = self.cartesian.re.cos() * self.cartesian.im.sinh();
651
652        Some(Self::new_cartesian(re, im))
653    }
654
655    /// Returns the cosine of the complex number.
656    ///
657    /// Returns `None` when the result is undefined or infinite.
658    ///
659    /// # Examples
660    ///
661    /// ```ignore
662    /// use complex_stuff::Complex;
663    ///
664    /// let complex = Complex::new_cartesian(5.0, 3.0);
665    ///
666    /// let result = complex.cos()?;
667    /// ```
668    pub fn cos(self) -> Option<Self> {
669        let re = self.cartesian.re.cos() * self.cartesian.im.cosh();
670        let im = -(self.cartesian.re.sin() * self.cartesian.im.sinh());
671
672        Some(Self::new_cartesian(re, im))
673    }
674}