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