1pub 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 expm1(self) -> Rectangular<FT> {
86 self.to_rectangular().expm1()
87 }
88
89 pub fn ln(self) -> Rectangular<FT> {
91 Rectangular::new(self.abs.ln(), self.arg)
92 }
93
94 pub fn ln_1p(self) -> Rectangular<FT> {
98 self.to_rectangular().ln_1p()
99 }
100
101 pub fn log2(self) -> Rectangular<FT> {
103 self.ln() / FT::LN_2()
104 }
105
106 pub fn log10(self) -> Rectangular<FT> {
108 self.ln() / FT::LN_10()
109 }
110
111 pub fn ln_branch(self, k: i32) -> Rectangular<FT> {
115 Rectangular::new(self.abs.ln(), self.arg + FT::TAU() * FT::from_i32(k))
116 }
117
118 pub fn ln_1p_branch(self, k: i32) -> Rectangular<FT> {
122 self.to_rectangular().ln_1p_branch(k)
123 }
124
125 pub fn log2_branch(self, k: i32) -> Rectangular<FT> {
127 self.ln_branch(k) / FT::LN_2()
128 }
129
130 pub fn log10_branch(self, k: i32) -> Rectangular<FT> {
132 self.ln_branch(k) / FT::LN_10()
133 }
134
135 pub fn sqrt_branch(self, k: i32) -> Self {
139 let two = FT::ONE + FT::ONE;
140 Self::new(
141 self.abs.sqrt(),
142 (self.arg + FT::TAU() * FT::from_i32(k)) / two,
143 )
144 }
145
146 pub fn nth_root(self, n: i32, k: i32) -> Self {
150 Self::new(
151 self.abs.powf(FT::from_i32(n).recip()),
152 (self.arg + FT::TAU() * FT::from_i32(k)) / FT::from_i32(n),
153 )
154 }
155
156 pub fn pow_rational(self, p: i32, q: i32, k: i32) -> Self {
161 self.nth_root(q, k).powi(p)
162 }
163
164 pub fn powf(self, x: FT) -> Self {
166 if x < FT::ZERO && self.abs == FT::ZERO {
167 return Self::ZERO;
168 }
169 Self::new(self.abs.powf(x), self.arg * x)
170 }
171
172 pub fn powi(self, n: i32) -> Self {
174 if n < 0 && self.abs == FT::ZERO {
175 return Self::ZERO;
176 }
177 Self::new(self.abs.powi(n), self.arg * FT::from_i32(n))
178 }
179
180 pub fn normalize(mut self) -> Self {
182 self.arg = self.arg.rem_euclid(&FT::TAU());
183 if self.abs < FT::ZERO {
184 self.abs = -self.abs;
185 if self.arg <= FT::ZERO {
186 self.arg += FT::PI();
187 } else {
188 self.arg -= FT::PI();
189 }
190 } else if self.arg > FT::PI() {
191 self.arg -= FT::TAU();
192 } else if self.arg <= -FT::PI() {
193 self.arg += FT::TAU();
194 }
195 self
196 }
197
198 pub fn is_finite(self) -> bool {
200 self.abs.is_finite() && self.arg.is_finite()
201 }
202}
203
204impl<FT: Number> Mul for ComplexPolar<FT> {
205 type Output = Self;
206 fn mul(mut self, other: Self) -> Self {
207 self *= other;
208 self
209 }
210}
211
212impl<FT: Number> Mul<FT> for ComplexPolar<FT> {
213 type Output = Self;
214 fn mul(mut self, re: FT) -> Self::Output {
215 self *= re;
216 self
217 }
218}
219
220impl<FT: Number> MulAssign for ComplexPolar<FT> {
221 fn mul_assign(&mut self, other: Self) {
222 self.abs *= other.abs;
223 self.arg += other.arg;
224 }
225}
226
227impl<FT: Number> MulAssign<FT> for ComplexPolar<FT> {
228 fn mul_assign(&mut self, re: FT) {
229 self.abs *= re;
230 }
231}
232
233impl<FT: Number> Div for ComplexPolar<FT> {
234 type Output = Self;
235 fn div(mut self, other: Self) -> Self {
236 self /= other;
237 self
238 }
239}
240
241impl<FT: Number> Div<FT> for ComplexPolar<FT> {
242 type Output = Self;
243 fn div(mut self, re: FT) -> Self {
244 self /= re;
245 self
246 }
247}
248
249impl<FT: Number> DivAssign for ComplexPolar<FT> {
250 fn div_assign(&mut self, other: Self) {
251 *self *= other.recip();
252 }
253}
254
255impl<FT: Number> DivAssign<FT> for ComplexPolar<FT> {
256 fn div_assign(&mut self, re: FT) {
257 self.abs /= re;
258 }
259}
260
261impl<FT: Number> Neg for ComplexPolar<FT> {
262 type Output = Self;
263 fn neg(mut self) -> Self {
264 self.abs = -self.abs;
265 self
266 }
267}
268
269impl<FT: Number + fmt::Display> fmt::Display for ComplexPolar<FT> {
270 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
271 fn fmt_x<FT: fmt::Display>(f: &mut fmt::Formatter, x: FT) -> fmt::Result {
272 if let Some(p) = f.precision() {
273 write!(f, "{x:.*}", p)
274 } else {
275 write!(f, "{x}")
276 }
277 }
278 let pi_radians = self.arg / FT::PI();
279 fmt_x(f, self.abs)?;
280 if pi_radians == FT::ZERO || self.abs == FT::ZERO {
281 Ok(())
282 } else if pi_radians == FT::ONE {
283 write!(f, "e^iπ")
284 } else {
285 write!(f, "e^")?;
286 fmt_x(f, pi_radians)?;
287 write!(f, "iπ")
288 }
289 }
290}
291
292impl<FT: Number> From<FT> for ComplexPolar<FT> {
293 fn from(value: FT) -> Self {
294 Self::new(value, FT::ZERO)
295 }
296}
297
298#[cfg(feature = "approx")]
299use approx::{AbsDiffEq, RelativeEq, UlpsEq};
300
301#[cfg(feature = "approx")]
302impl<FT: AbsDiffEq + Copy> AbsDiffEq for ComplexPolar<FT>
303where
304 <FT as AbsDiffEq>::Epsilon: Copy,
305{
306 type Epsilon = <FT as AbsDiffEq>::Epsilon;
307 fn default_epsilon() -> Self::Epsilon {
308 FT::default_epsilon()
309 }
310 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
311 FT::abs_diff_eq(&self.abs, &other.abs, epsilon)
312 && FT::abs_diff_eq(&self.arg, &other.arg, epsilon)
313 }
314}
315
316#[cfg(feature = "approx")]
317impl<FT: RelativeEq + Copy> RelativeEq for ComplexPolar<FT>
318where
319 <FT as AbsDiffEq>::Epsilon: Copy,
320{
321 fn default_max_relative() -> Self::Epsilon {
322 FT::default_max_relative()
323 }
324 fn relative_eq(
325 &self,
326 other: &Self,
327 epsilon: Self::Epsilon,
328 max_relative: Self::Epsilon,
329 ) -> bool {
330 FT::relative_eq(&self.abs, &other.abs, epsilon, max_relative)
331 && FT::relative_eq(&self.arg, &other.arg, epsilon, max_relative)
332 }
333}
334
335#[cfg(feature = "approx")]
336impl<FT: UlpsEq + Copy> UlpsEq for ComplexPolar<FT>
337where
338 <FT as AbsDiffEq>::Epsilon: Copy,
339{
340 fn default_max_ulps() -> u32 {
341 FT::default_max_ulps()
342 }
343 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
344 FT::ulps_eq(&self.abs, &other.abs, epsilon, max_ulps)
345 && FT::ulps_eq(&self.arg, &other.arg, epsilon, max_ulps)
346 }
347}