common_stdx/
complex_number.rs1use 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 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 let inf = T::from(f64::INFINITY).unwrap_or(rhs.real); ComplexNum::new(inf, inf)
64 } else {
65 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 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}