abels_complex/complex/
polar.rs1pub type ComplexPolar32 = ComplexPolar<f32>;
2pub type ComplexPolar64 = ComplexPolar<f64>;
3use crate::traits::Number;
4use core::fmt;
5
6use super::Complex as Rectangular;
7use core::ops::*;
8
9#[inline(always)]
11#[must_use]
12pub const fn complex_polar<FT>(abs: FT, arg: FT) -> ComplexPolar<FT> {
13 ComplexPolar::new(abs, arg)
14}
15
16#[derive(Clone, Copy, PartialEq, Debug, Default)]
18#[repr(C)]
19pub struct ComplexPolar<FT> {
20 pub abs: FT,
21 pub arg: FT,
22}
23
24impl<FT> ComplexPolar<FT> {
25 pub const fn new(abs: FT, arg: FT) -> Self {
27 Self { abs, arg }
28 }
29}
30
31impl<FT: Number> ComplexPolar<FT> {
32 pub const ZERO: Self = Self::new(FT::ZERO, FT::ZERO);
33 pub const ONE: Self = Self::new(FT::ONE, FT::ZERO);
34
35 pub fn conjugate(self) -> Self {
37 Self::new(self.abs, -self.arg)
38 }
39
40 pub fn re(self) -> FT {
42 self.abs * self.arg.cos()
43 }
44
45 pub fn im(self) -> FT {
47 self.abs * self.arg.sin()
48 }
49
50 pub fn abs_sq(self) -> FT {
52 self.abs * self.abs
53 }
54
55 pub fn recip(self) -> Self {
57 Self::new(self.abs.recip(), -self.arg)
58 }
59
60 pub fn sqrt(self) -> Self {
62 let two = FT::ONE + FT::ONE;
63 Self::new(self.abs.sqrt(), self.arg / two)
64 }
65
66 pub fn to_rectangular(self) -> Rectangular<FT> {
68 let (sin, cos) = self.arg.sin_cos();
69 Rectangular::new(cos, sin) * self.abs
70 }
71
72 pub fn exp(self) -> Self {
74 self.to_rectangular().exp()
75 }
76
77 pub fn exp2(self) -> Self {
79 self.to_rectangular().exp2()
80 }
81
82 pub fn ln(self) -> Rectangular<FT> {
84 Rectangular::new(self.abs.ln(), self.arg)
85 }
86
87 pub fn log2(self) -> Rectangular<FT> {
89 self.ln() / FT::LN_2()
90 }
91
92 pub fn log10(self) -> Rectangular<FT> {
94 self.ln() / FT::LN_10()
95 }
96
97 pub fn powf(self, x: FT) -> Self {
99 if x < FT::ZERO && self.abs == FT::ZERO {
100 return Self::ZERO;
101 }
102 Self::new(self.abs.powf(x), self.arg * x)
103 }
104
105 pub fn powi(self, n: i32) -> Self {
107 if n < 0 && self.abs == FT::ZERO {
108 return Self::ZERO;
109 }
110 Self::new(self.abs.powi(n), self.arg * FT::from_i32(n))
111 }
112
113 pub fn normalize(mut self) -> Self {
115 self.arg = self.arg.rem_euclid(&FT::TAU());
116 if self.abs < FT::ZERO {
117 self.abs = -self.abs;
118 if self.arg <= FT::ZERO {
119 self.arg += FT::PI();
120 } else {
121 self.arg -= FT::PI();
122 }
123 } else if self.arg > FT::PI() {
124 self.arg -= FT::TAU();
125 } else if self.arg <= -FT::PI() {
126 self.arg += FT::TAU();
127 }
128 self
129 }
130}
131
132impl<FT: Number> Mul for ComplexPolar<FT> {
133 type Output = Self;
134 fn mul(mut self, other: Self) -> Self {
135 self *= other;
136 self
137 }
138}
139
140impl<FT: Number> Mul<FT> for ComplexPolar<FT> {
141 type Output = Self;
142 fn mul(mut self, re: FT) -> Self::Output {
143 self *= re;
144 self
145 }
146}
147
148impl<FT: Number> MulAssign for ComplexPolar<FT> {
149 fn mul_assign(&mut self, other: Self) {
150 self.abs *= other.abs;
151 self.arg += other.arg;
152 }
153}
154
155impl<FT: Number> MulAssign<FT> for ComplexPolar<FT> {
156 fn mul_assign(&mut self, re: FT) {
157 self.abs *= re;
158 }
159}
160
161impl<FT: Number> Div for ComplexPolar<FT> {
162 type Output = Self;
163 fn div(mut self, other: Self) -> Self {
164 self /= other;
165 self
166 }
167}
168
169impl<FT: Number> Div<FT> for ComplexPolar<FT> {
170 type Output = Self;
171 fn div(mut self, re: FT) -> Self {
172 self /= re;
173 self
174 }
175}
176
177impl<FT: Number> DivAssign for ComplexPolar<FT> {
178 fn div_assign(&mut self, other: Self) {
179 *self *= other.recip();
180 }
181}
182
183impl<FT: Number> DivAssign<FT> for ComplexPolar<FT> {
184 fn div_assign(&mut self, re: FT) {
185 self.abs /= re;
186 }
187}
188
189impl<FT: Number> Neg for ComplexPolar<FT> {
190 type Output = Self;
191 fn neg(mut self) -> Self {
192 self.abs = -self.abs;
193 self
194 }
195}
196
197impl<FT: Number + fmt::Display> fmt::Display for ComplexPolar<FT> {
198 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199 fn fmt_x<FT: fmt::Display>(f: &mut fmt::Formatter, x: FT) -> fmt::Result {
200 if let Some(p) = f.precision() {
201 write!(f, "{x:.*}", p)
202 } else {
203 write!(f, "{x}")
204 }
205 }
206 let pi_radians = self.arg / FT::PI();
207 fmt_x(f, self.abs)?;
208 if pi_radians == FT::ZERO || self.abs == FT::ZERO {
209 Ok(())
210 } else if pi_radians == FT::ONE {
211 write!(f, "e^iπ")
212 } else {
213 write!(f, "e^")?;
214 fmt_x(f, pi_radians)?;
215 write!(f, "iπ")
216 }
217 }
218}
219
220impl<FT: Number> From<FT> for ComplexPolar<FT> {
221 fn from(value: FT) -> Self {
222 Self::new(value, FT::ZERO)
223 }
224}
225
226#[cfg(feature = "approx")]
227use approx::{AbsDiffEq, RelativeEq, UlpsEq};
228
229#[cfg(feature = "approx")]
230impl<FT: AbsDiffEq + Copy> AbsDiffEq for ComplexPolar<FT>
231where
232 <FT as AbsDiffEq>::Epsilon: Copy,
233{
234 type Epsilon = <FT as AbsDiffEq>::Epsilon;
235 fn default_epsilon() -> Self::Epsilon {
236 FT::default_epsilon()
237 }
238 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
239 FT::abs_diff_eq(&self.abs, &other.abs, epsilon)
240 && FT::abs_diff_eq(&self.arg, &other.arg, epsilon)
241 }
242}
243
244#[cfg(feature = "approx")]
245impl<FT: RelativeEq + Copy> RelativeEq for ComplexPolar<FT>
246where
247 <FT as AbsDiffEq>::Epsilon: Copy,
248{
249 fn default_max_relative() -> Self::Epsilon {
250 FT::default_max_relative()
251 }
252 fn relative_eq(
253 &self,
254 other: &Self,
255 epsilon: Self::Epsilon,
256 max_relative: Self::Epsilon,
257 ) -> bool {
258 FT::relative_eq(&self.abs, &other.abs, epsilon, max_relative)
259 && FT::relative_eq(&self.arg, &other.arg, epsilon, max_relative)
260 }
261}
262
263#[cfg(feature = "approx")]
264impl<FT: UlpsEq + Copy> UlpsEq for ComplexPolar<FT>
265where
266 <FT as AbsDiffEq>::Epsilon: Copy,
267{
268 fn default_max_ulps() -> u32 {
269 FT::default_max_ulps()
270 }
271 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
272 FT::ulps_eq(&self.abs, &other.abs, epsilon, max_ulps)
273 && FT::ulps_eq(&self.arg, &other.arg, epsilon, max_ulps)
274 }
275}