Skip to main content

common_stdx/
complex_number.rs

1use num_traits::Num;
2use num_traits::NumCast;
3use std::ops::Div;
4
5#[derive(Copy, Clone)]
6pub struct ComplexNum<T: Num + Copy> {
7    pub real: T,
8    pub imaginary: T,
9}
10
11impl<T> ComplexNum<T>
12where
13    T: Copy + Clone + NumCast + Num,
14{
15    pub fn new(real: T, imaginary: T) -> Self {
16        ComplexNum { real, imaginary }
17    }
18
19    pub fn conjugate(self) -> Self {
20        ComplexNum::new(self.real, T::zero() - self.imaginary)
21    }
22
23    pub fn as_tuple(self) -> (T, T) {
24        (self.real, self.imaginary)
25    }
26
27    pub fn from_polar(polar: ComplexPolar<T>) -> Option<Self> {
28        let radius = polar.radius.to_f64()?;
29        let angle = polar.angle.to_f64()?;
30
31        let real_f64 = radius * angle.cos();
32        let imaginary_f64 = radius * angle.sin();
33
34        Some(ComplexNum {
35            real: NumCast::from(real_f64)?,
36            imaginary: NumCast::from(imaginary_f64)?,
37        })
38    }
39    pub fn as_polar(&self) -> Option<ComplexPolar<T>> {
40        let a = self.real.to_f64()?;
41        let b = self.imaginary.to_f64()?;
42
43        let radius = (a * a + b * b).sqrt();
44        let angle = b.atan2(a);
45
46        Some(ComplexPolar {
47            radius: NumCast::from(radius)?,
48            angle: NumCast::from(angle)?,
49        })
50    }
51
52    pub fn safe_div(self, rhs: Self) -> Self {
53        // Compute denominator magnitude as f64 for safe comparison
54        let denom_mag_f64 = {
55            let real_f64 = rhs.real.to_f64().unwrap_or(0.0);
56            let imag_f64 = rhs.imaginary.to_f64().unwrap_or(0.0);
57            real_f64 * real_f64 + imag_f64 * imag_f64
58        };
59
60        if denom_mag_f64.abs() < 1e-12 {
61            // division by zero = inf
62            let inf = T::from(f64::INFINITY).unwrap_or(rhs.real); // fallback if cast fails
63            ComplexNum::new(inf, inf)
64        } else {
65            // Standard complex division using conjugate
66            let numer = self * rhs.conjugate();
67            ComplexNum::new(
68                numer.real / rhs.real * rhs.real + rhs.imaginary * rhs.imaginary,
69                numer.imaginary / rhs.real * rhs.real + rhs.imaginary * rhs.imaginary,
70            )
71        }
72    }
73}
74
75#[derive(Copy, Clone)]
76pub struct ComplexPolar<T: Num + Copy> {
77    radius: T,
78    angle: T,
79}
80
81impl<T> ComplexPolar<T>
82where
83    T: Num + Copy,
84{
85    pub fn get_radius(&self) -> T {
86        self.radius
87    }
88    pub fn get_angle(&self) -> T {
89        self.angle
90    }
91}
92
93impl<T> std::ops::Add for ComplexNum<T>
94where
95    T: Num + Copy + Clone + NumCast,
96{
97    type Output = ComplexNum<T>;
98
99    fn add(self, rhs: Self) -> Self::Output {
100        ComplexNum::new(self.real + rhs.real, self.imaginary + rhs.imaginary)
101    }
102}
103
104impl<T> std::ops::Sub for ComplexNum<T>
105where
106    T: Num + Copy + Clone + NumCast,
107{
108    type Output = ComplexNum<T>;
109
110    fn sub(self, rhs: Self) -> Self::Output {
111        ComplexNum::new(self.real - rhs.real, self.imaginary - rhs.imaginary)
112    }
113}
114
115impl<T> std::ops::Mul for ComplexNum<T>
116where
117    T: Num + Copy + Clone + NumCast,
118{
119    type Output = ComplexNum<T>;
120
121    fn mul(self, rhs: Self) -> Self::Output {
122        // (a + bi)(c + di) = (ac - bd) + (ad + bc)i
123        ComplexNum::new(
124            self.real * rhs.real - self.imaginary * rhs.imaginary,
125            self.real * rhs.imaginary + self.imaginary * rhs.real,
126        )
127    }
128}
129
130impl<T> std::ops::Div for ComplexNum<T>
131where
132    T: Num + Copy + Div<Output = T> + Clone + NumCast,
133{
134    type Output = ComplexNum<T>;
135
136    fn div(self, rhs: Self) -> Self::Output {
137        let denom = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary;
138        let numer = self * rhs.conjugate();
139
140        ComplexNum::new(numer.real / denom, numer.imaginary / denom)
141    }
142}