1use core::f32::consts::{FRAC_PI_2, PI, TAU};
2use core::fmt;
3use core::ops::*;
4use core::write;
5#[cfg(feature = "libm")]
6use num_traits::real::Real;
7
8use crate::rectangular::*;
9
10#[inline(always)]
12#[must_use]
13pub const fn complex_polar(abs: f32, arg: f32) -> ComplexPolar {
14 ComplexPolar::new(abs, arg)
15}
16
17#[derive(Clone, Copy, PartialEq, Debug)]
18#[repr(C)]
19pub struct ComplexPolar {
20 pub abs: f32,
21 pub arg: f32,
22}
23
24impl ComplexPolar {
25 pub const ZERO: Self = complex_polar(0.0, 0.0);
26 pub const ONE: Self = complex_polar(1.0, 0.0);
27 pub const I: Self = complex_polar(1.0, FRAC_PI_2);
28 pub const NEG_ONE: Self = complex_polar(1.0, PI);
29 pub const NEG_I: Self = complex_polar(1.0, -FRAC_PI_2);
30
31 pub const fn new(abs: f32, arg: f32) -> Self {
32 Self { abs, arg }
33 }
34
35 pub const fn conjugate(self) -> Self {
36 complex_polar(self.abs, -self.arg)
37 }
38
39 pub fn re(self) -> f32 {
40 self.to_rectangular().re
41 }
42
43 pub fn im(self) -> f32 {
44 self.to_rectangular().im
45 }
46
47 pub const fn abs_sq(self) -> f32 {
48 self.abs * self.abs
49 }
50
51 pub fn recip(self) -> Self {
52 self.conjugate() / self.abs_sq()
53 }
54
55 pub fn sqrt(self) -> Self {
56 complex_polar(self.abs.sqrt(), self.arg / 2.0)
57 }
58
59 pub fn to_rectangular(self) -> Complex {
60 let (sin, cos) = self.arg.sin_cos();
61 self.abs * complex(cos, sin)
62 }
63
64 pub fn exp(self) -> Self {
65 self.to_rectangular().exp()
66 }
67
68 pub fn log(self) -> Complex {
69 complex(self.abs.ln(), self.arg)
70 }
71
72 pub fn powf(self, x: f32) -> Self {
73 complex_polar(self.abs.powf(x), self.arg * x)
74 }
75
76 pub fn powi(self, n: i32) -> Self {
77 complex_polar(self.abs.powi(n), self.arg * n as f32)
78 }
79
80 pub fn normalize(mut self) -> Self {
81 #[cfg(feature = "libm")]
82 {
83 self.arg = num_traits::Euclid::rem_euclid(&self.arg, &TAU);
84 }
85 #[cfg(not(feature = "libm"))]
86 {
87 self.arg = self.arg.rem_euclid(TAU);
88 }
89 if self.abs < 0.0 {
90 self.abs = -self.abs;
91 if self.arg <= 0.0 {
92 self.arg += PI;
93 } else {
94 self.arg -= PI;
95 }
96 } else {
97 if self.arg > PI {
98 self.arg -= TAU;
99 } else if self.arg <= -PI {
100 self.arg += TAU;
101 }
102 }
103 self
104 }
105}
106
107impl Mul for ComplexPolar {
108 type Output = Self;
109 fn mul(mut self, other: Self) -> Self::Output {
110 self *= other;
111 self
112 }
113}
114
115impl Mul<f32> for ComplexPolar {
116 type Output = Self;
117 fn mul(mut self, re: f32) -> Self::Output {
118 self *= re;
119 self
120 }
121}
122
123impl Mul<ComplexPolar> for f32 {
124 type Output = ComplexPolar;
125 fn mul(self, mut other: ComplexPolar) -> Self::Output {
126 other *= self;
127 other
128 }
129}
130
131impl MulAssign for ComplexPolar {
132 fn mul_assign(&mut self, other: Self) {
133 self.abs *= other.abs;
134 self.arg += other.arg;
135 }
136}
137
138impl MulAssign<f32> for ComplexPolar {
139 fn mul_assign(&mut self, re: f32) {
140 self.abs *= re;
141 }
142}
143
144impl Div for ComplexPolar {
145 type Output = Self;
146 fn div(mut self, other: Self) -> Self::Output {
147 self /= other;
148 self
149 }
150}
151
152impl Div<f32> for ComplexPolar {
153 type Output = Self;
154 fn div(mut self, re: f32) -> Self::Output {
155 self /= re;
156 self
157 }
158}
159
160impl Div<ComplexPolar> for f32 {
161 type Output = ComplexPolar;
162 fn div(self, other: ComplexPolar) -> Self::Output {
163 self * other.conjugate() / other.abs_sq()
164 }
165}
166
167impl DivAssign for ComplexPolar {
168 fn div_assign(&mut self, other: Self) {
169 *self *= other.conjugate();
170 *self /= other.abs_sq();
171 }
172}
173
174impl DivAssign<f32> for ComplexPolar {
175 fn div_assign(&mut self, re: f32) {
176 self.abs /= re;
177 }
178}
179
180impl Neg for ComplexPolar {
181 type Output = Self;
182 fn neg(mut self) -> Self::Output {
183 self.abs = -self.abs;
184 self
185 }
186}
187
188impl fmt::Display for ComplexPolar {
189 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
190 fn fmt_x(f: &mut fmt::Formatter, x: f32) -> fmt::Result {
191 if let Some(p) = f.precision() {
192 write!(f, "{x:.*}", p)
193 } else {
194 write!(f, "{x}")
195 }
196 }
197 let pi_radians = self.arg / PI;
198 fmt_x(f, self.abs)?;
199 if pi_radians == 0.0 || self.abs == 0.0 {
200 Ok(())
201 } else if pi_radians == 1.0 {
202 write!(f, "e^iπ")
203 } else {
204 write!(f, "e^")?;
205 fmt_x(f, pi_radians)?;
206 write!(f, "iπ")
207 }
208 }
209}
210
211#[cfg(feature = "rand")]
212impl rand::distr::Distribution<ComplexPolar> for rand::distr::StandardUniform {
213 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> ComplexPolar {
214 complex_polar(self.sample(rng), rng.random_range((-PI).next_up()..=PI))
215 }
216}
217
218#[cfg(feature = "approx")]
219use approx::{AbsDiffEq, RelativeEq, UlpsEq};
220
221#[cfg(feature = "approx")]
222impl AbsDiffEq for ComplexPolar {
223 type Epsilon = <f32 as AbsDiffEq>::Epsilon;
224 fn default_epsilon() -> Self::Epsilon {
225 f32::default_epsilon()
226 }
227 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
228 f32::abs_diff_eq(&self.abs, &other.abs, epsilon)
229 && f32::abs_diff_eq(&self.arg, &other.arg, epsilon)
230 }
231}
232
233#[cfg(feature = "approx")]
234impl RelativeEq for ComplexPolar {
235 fn default_max_relative() -> Self::Epsilon {
236 f32::default_max_relative()
237 }
238 fn relative_eq(
239 &self,
240 other: &Self,
241 epsilon: Self::Epsilon,
242 max_relative: Self::Epsilon,
243 ) -> bool {
244 f32::relative_eq(&self.abs, &other.abs, epsilon, max_relative)
245 && f32::relative_eq(&self.arg, &other.arg, epsilon, max_relative)
246 }
247}
248
249#[cfg(feature = "approx")]
250impl UlpsEq for ComplexPolar {
251 fn default_max_ulps() -> u32 {
252 f32::default_max_ulps()
253 }
254 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
255 f32::ulps_eq(&self.abs, &other.abs, epsilon, max_ulps)
256 && f32::ulps_eq(&self.arg, &other.arg, epsilon, max_ulps)
257 }
258}
259
260impl From<f32> for ComplexPolar {
261 fn from(value: f32) -> Self {
262 complex_polar(value, 0.0)
263 }
264}
265
266#[cfg(test)]
267mod tests {
268 use super::*;
269 use approx::*;
270 use core::f32::consts::{E, FRAC_PI_2, PI};
271 use rand::{
272 distr::{uniform::*, Distribution, StandardUniform, Uniform},
273 rngs::StdRng,
274 Rng, SeedableRng,
275 };
276
277 const NUM_SAMPLES: usize = 100;
278
279 fn random_samples<T>() -> impl core::iter::Iterator<Item = T>
280 where
281 StandardUniform: Distribution<T>,
282 {
283 StdRng::seed_from_u64(21)
284 .sample_iter(StandardUniform)
285 .take(NUM_SAMPLES)
286 }
287
288 fn uniform_samples<T>(low: T, high: T) -> impl core::iter::Iterator<Item = T>
289 where
290 T: SampleUniform,
291 {
292 StdRng::seed_from_u64(21)
293 .sample_iter(Uniform::new(low, high).unwrap())
294 .take(NUM_SAMPLES)
295 }
296
297 #[test]
298 fn multiplication() {
299 for z0 in random_samples::<ComplexPolar>() {
300 for z1 in random_samples::<ComplexPolar>() {
301 let z = z0 * z1;
302 assert_eq!(z.abs, z0.abs * z1.abs);
303 assert_eq!(z.arg, z0.arg + z1.arg);
304
305 let z = z0 * z1.re();
306 assert_eq!(z.normalize().abs, z0.abs * z1.re().abs());
307 assert_eq!(z.arg, z0.arg);
308
309 let z = z0.re() * z1;
310 assert_eq!(z.normalize().abs, z0.re().abs() * z1.abs);
311 assert_eq!(z.arg, z1.arg);
312
313 let mut z = z0;
314 z *= z1;
315 assert_eq!(z, z0 * z1);
316
317 let mut z = z0;
318 z *= z1.re();
319 assert_eq!(z, z0 * z1.re());
320 }
321 assert_eq!(z0 * ComplexPolar::ONE, z0);
322 assert_eq!((z0 * ComplexPolar::ZERO).abs, 0.0);
323 assert_eq!((z0 * 0.0).abs, 0.0);
324 }
325 }
326
327 #[test]
328 fn division() {
329 for z0 in random_samples::<ComplexPolar>() {
330 for z1 in random_samples::<ComplexPolar>() {
331 let z = z0 / z1;
332 assert_ulps_eq!(z.abs, z0.abs / z1.abs);
333 assert_ulps_eq!(z.arg, z0.arg - z1.arg);
334
335 let z = z0 / z1.re();
336 assert_ulps_eq!(z.normalize().abs, z0.abs / z1.re().abs());
337 assert_ulps_eq!(z.arg, z0.arg);
338
339 let z = z0.re() / z1;
340 assert_ulps_eq!(z.normalize().abs, z0.re().abs() / z1.abs);
341 assert_ulps_eq!(z.arg, -z1.arg);
342
343 let mut z = z0;
344 z /= z1;
345 assert_eq!(z, z0 / z1);
346
347 let mut z = z0;
348 z /= z1.re();
349 assert_eq!(z, z0 / z1.re());
350 }
351 assert_eq!(z0 / z0, ComplexPolar::ONE);
352 assert_eq!((ComplexPolar::ZERO / z0).abs, 0.0);
353 }
354 }
355
356 #[test]
357 fn negation() {
358 assert_eq!((-ComplexPolar::ONE).normalize(), ComplexPolar::NEG_ONE);
359 assert_eq!((-ComplexPolar::I).normalize(), ComplexPolar::NEG_I);
360 assert_eq!((-ComplexPolar::NEG_ONE).normalize(), ComplexPolar::ONE);
361 assert_ulps_eq!((-ComplexPolar::NEG_I).normalize(), ComplexPolar::I);
362 }
363
364 #[test]
365 fn reciprocal() {
366 for z in random_samples::<ComplexPolar>() {
367 assert_eq!(z.recip(), 1.0 / z);
368 assert_ulps_eq!(z * z.recip(), ComplexPolar::ONE);
369 }
370 assert_eq!(ComplexPolar::ONE.recip(), ComplexPolar::ONE);
371 assert_eq!(ComplexPolar::I.recip(), ComplexPolar::NEG_I);
372 assert_eq!(
373 ComplexPolar::NEG_ONE.recip().normalize(),
374 ComplexPolar::NEG_ONE
375 );
376 assert_eq!(ComplexPolar::NEG_I.recip(), ComplexPolar::I);
377 }
378
379 #[test]
380 fn sqrt() {
381 for z in random_samples::<ComplexPolar>() {
382 assert_eq!(z.sqrt().abs, z.abs.sqrt());
383 assert_eq!(z.sqrt().arg, z.arg / 2.0);
384 }
385 assert_eq!(ComplexPolar::ONE.sqrt(), ComplexPolar::ONE);
386 assert_eq!(ComplexPolar::NEG_ONE.sqrt(), ComplexPolar::I);
387 assert_eq!(ComplexPolar::ONE.sqrt(), ComplexPolar::ONE);
388 }
389
390 #[test]
391 fn abs() {
392 for z in random_samples::<ComplexPolar>() {
393 assert_eq!(z.abs_sq(), z.abs * z.abs);
394 }
395 assert_eq!(ComplexPolar::ONE.abs, 1.0);
396 assert_eq!(ComplexPolar::I.abs, 1.0);
397 assert_eq!(ComplexPolar::NEG_ONE.abs, 1.0);
398 assert_eq!(ComplexPolar::NEG_I.abs, 1.0);
399 }
400
401 #[test]
402 fn conjugate() {
403 for z in random_samples::<ComplexPolar>() {
404 assert_eq!(z.conjugate().re(), z.re());
405 assert_eq!(z.conjugate().im(), -z.im());
406 assert_eq!(z.conjugate().conjugate(), z);
407 }
408 assert_ulps_eq!(ComplexPolar::ONE.conjugate().normalize(), ComplexPolar::ONE);
409 assert_ulps_eq!(ComplexPolar::I.conjugate().normalize(), ComplexPolar::NEG_I);
410 assert_ulps_eq!(
411 ComplexPolar::NEG_ONE.conjugate().normalize(),
412 ComplexPolar::NEG_ONE
413 );
414 assert_ulps_eq!(ComplexPolar::NEG_I.conjugate().normalize(), ComplexPolar::I);
415 }
416
417 #[test]
418 fn arg() {
419 assert_eq!(ComplexPolar::ONE.arg, 0.0);
420 assert_eq!(ComplexPolar::I.arg, FRAC_PI_2);
421 assert_eq!(ComplexPolar::NEG_ONE.arg, PI);
422 assert_eq!(ComplexPolar::NEG_I.arg, -FRAC_PI_2);
423 }
424
425 #[test]
426 fn exp() {
427 for z in random_samples::<ComplexPolar>() {
428 assert_eq!(z.exp().abs, z.re().exp());
429 assert_eq!(z.exp().arg, z.im());
430 assert_ulps_eq!(z.exp().log(), z.to_rectangular());
431 }
432 assert_ulps_eq!(ComplexPolar::ONE.exp(), complex_polar(E, 0.0));
433 assert_ulps_eq!(ComplexPolar::I.exp(), complex_polar(1.0, 1.0));
434 assert_ulps_eq!(ComplexPolar::NEG_ONE.exp(), complex_polar(E.recip(), 0.0));
435 assert_ulps_eq!(ComplexPolar::NEG_I.exp(), complex_polar(1.0, -1.0));
436 }
437
438 #[test]
439 fn log() {
440 for z in random_samples::<ComplexPolar>() {
441 assert_eq!(z.log().re, z.abs.ln());
442 assert_eq!(z.log().im, z.arg);
443 assert_ulps_eq!(z.log().exp(), z);
444 }
445 assert_eq!(ComplexPolar::ONE.log(), Complex::ZERO);
446 assert_eq!(ComplexPolar::I.log(), Complex::I * FRAC_PI_2);
447 assert_eq!(ComplexPolar::NEG_ONE.log(), Complex::I * PI);
448 assert_eq!(ComplexPolar::NEG_I.log(), Complex::I * -FRAC_PI_2);
449 }
450
451 #[test]
452 fn powi() {
453 for z in random_samples::<ComplexPolar>() {
454 assert_eq!(z.powi(0), ComplexPolar::ONE);
455 assert_eq!(z.powi(1), z);
456 for n in random_samples::<i32>() {
457 assert_eq!(z.powi(n).abs, z.abs.powi(n));
458 assert_eq!(z.powi(n).arg, z.arg * n as f32);
459 }
460 }
461 for n in random_samples::<i32>() {
462 assert_eq!(ComplexPolar::ZERO.powi(n.abs()), ComplexPolar::ZERO);
463 assert_eq!(ComplexPolar::ONE.powi(n), ComplexPolar::ONE);
464 }
465 }
466
467 #[test]
468 fn powf() {
469 for z in random_samples::<ComplexPolar>() {
470 assert_eq!(z.powf(0.0), ComplexPolar::ONE);
471 assert_eq!(z.powf(1.0), z);
472 for n in random_samples::<i32>() {
473 let x = n as f32 * 0.01;
474 assert_eq!(z.powf(x).abs, z.abs.powf(x));
475 assert_eq!(z.powf(x).arg, z.arg * x);
476 }
477 }
478 for n in random_samples::<i32>() {
479 let x = n as f32 * 0.01;
480 assert_eq!(ComplexPolar::ZERO.powf(x.abs()), ComplexPolar::ZERO);
481 assert_eq!(ComplexPolar::ONE.powf(x), ComplexPolar::ONE);
482 }
483 }
484
485 #[test]
486 fn normalize() {
487 for z in random_samples::<ComplexPolar>() {
488 for n in uniform_samples::<i32>(-99, 99) {
489 let w = complex_polar(z.abs, z.arg + n as f32 * TAU);
490 assert_ulps_eq!(z, w.normalize(), epsilon = 2000.0 * f32::EPSILON);
491
492 assert_ulps_eq!(
493 complex_polar(-z.abs, z.arg).normalize(),
494 complex_polar(z.abs, z.arg + PI).normalize(),
495 epsilon = 2000.0 * f32::EPSILON
496 );
497 }
498 }
499 }
500
501 }