abels_complex/complex/f32/
polar.rs1use core::f32::consts::{FRAC_PI_2, PI};
2use core::ops::*;
3
4type Polar = crate::complex::polar::ComplexPolar<FT>;
5type FT = f32;
6
7impl Mul<Polar> for FT {
8 type Output = Polar;
9 fn mul(self, mut other: Self::Output) -> Self::Output {
10 other *= self;
11 other
12 }
13}
14
15impl Div<Polar> for FT {
16 type Output = Polar;
17 fn div(self, other: Self::Output) -> Self::Output {
18 self * other.recip()
19 }
20}
21
22impl Polar {
23 pub const I: Self = Self::new(1.0, FRAC_PI_2);
24 pub const NEG_ONE: Self = Self::new(1.0, PI);
25 pub const NEG_I: Self = Self::new(1.0, -FRAC_PI_2);
26}
27
28#[cfg(feature = "rand")]
29impl rand::distr::Distribution<Polar> for rand::distr::StandardUniform {
30 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Polar {
31 Polar::new(self.sample(rng), rng.random_range((-PI).next_up()..=PI))
32 }
33}
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38 use approx::*;
39 use core::f32::consts::{E, LN_2, TAU};
40 use rand::{
41 Rng, SeedableRng,
42 distr::{Distribution, StandardUniform, Uniform, uniform::*},
43 rngs::StdRng,
44 };
45
46 type Rectangular = crate::complex::rectangular::Complex<FT>;
47
48 const NUM_SAMPLES: usize = 100;
49 const SEED: u64 = 21;
50
51 fn random_samples<T>() -> impl core::iter::Iterator<Item = T>
52 where
53 StandardUniform: Distribution<T>,
54 {
55 StdRng::seed_from_u64(SEED)
56 .sample_iter(StandardUniform)
57 .take(NUM_SAMPLES)
58 }
59
60 fn uniform_samples<T>(low: T, high: T) -> impl core::iter::Iterator<Item = T>
61 where
62 T: SampleUniform,
63 {
64 StdRng::seed_from_u64(SEED)
65 .sample_iter(Uniform::new(low, high).unwrap())
66 .take(NUM_SAMPLES)
67 }
68
69 #[test]
70 fn multiplication() {
71 for z0 in random_samples::<Polar>() {
72 for z1 in random_samples::<Polar>() {
73 let z = z0 * z1;
74 assert_eq!(z.abs, z0.abs * z1.abs);
75 assert_eq!(z.arg, z0.arg + z1.arg);
76
77 let z = z0 * z1.re();
78 assert_eq!(z.normalize().abs, z0.abs * z1.re().abs());
79 assert_eq!(z.arg, z0.arg);
80
81 let z = z0.re() * z1;
82 assert_eq!(z.normalize().abs, z0.re().abs() * z1.abs);
83 assert_eq!(z.arg, z1.arg);
84
85 let mut z = z0;
86 z *= z1;
87 assert_eq!(z, z0 * z1);
88
89 let mut z = z0;
90 z *= z1.re();
91 assert_eq!(z, z0 * z1.re());
92 }
93 assert_eq!(z0 * Polar::ONE, z0);
94 assert_eq!((z0 * Polar::ZERO).abs, 0.0);
95 assert_eq!((z0 * 0.0).abs, 0.0);
96 }
97 }
98
99 #[test]
100 fn division() {
101 for z0 in random_samples::<Polar>() {
102 for z1 in random_samples::<Polar>() {
103 let z = z0 / z1;
104 assert_ulps_eq!(z.abs, z0.abs / z1.abs);
105 assert_ulps_eq!(z.arg, z0.arg - z1.arg);
106
107 let z = z0 / z1.re();
108 assert_ulps_eq!(z.normalize().abs, z0.abs / z1.re().abs());
109 assert_ulps_eq!(z.arg, z0.arg);
110
111 let z = z0.re() / z1;
112 assert_ulps_eq!(z.normalize().abs, z0.re().abs() / z1.abs);
113 assert_ulps_eq!(z.arg, -z1.arg);
114
115 let mut z = z0;
116 z /= z1;
117 assert_eq!(z, z0 / z1);
118
119 let mut z = z0;
120 z /= z1.re();
121 assert_eq!(z, z0 / z1.re());
122 }
123 assert_ulps_eq!(z0 / z0, Polar::ONE);
124 assert_eq!((Polar::ZERO / z0).abs, 0.0);
125 }
126 }
127
128 #[test]
129 fn negation() {
130 assert_eq!((-Polar::ONE).normalize(), Polar::NEG_ONE);
131 assert_eq!((-Polar::I).normalize(), Polar::NEG_I);
132 assert_eq!((-Polar::NEG_ONE).normalize(), Polar::ONE);
133 assert_ulps_eq!((-Polar::NEG_I).normalize(), Polar::I);
134 }
135
136 #[test]
137 fn reciprocal() {
138 for z in random_samples::<Polar>() {
139 assert_ulps_eq!(z.recip(), 1.0 / z);
140 assert_ulps_eq!(z * z.recip(), Polar::ONE);
141 }
142 assert_eq!(Polar::ONE.recip(), Polar::ONE);
143 assert_eq!(Polar::I.recip(), Polar::NEG_I);
144 assert_eq!(Polar::NEG_ONE.recip().normalize(), Polar::NEG_ONE);
145 assert_eq!(Polar::NEG_I.recip(), Polar::I);
146 }
147
148 #[test]
149 fn sqrt() {
150 for z in random_samples::<Polar>() {
151 assert_eq!(z.sqrt().abs, z.abs.sqrt());
152 assert_eq!(z.sqrt().arg, z.arg / 2.0);
153 }
154 assert_eq!(Polar::ONE.sqrt(), Polar::ONE);
155 assert_eq!(Polar::NEG_ONE.sqrt(), Polar::I);
156 assert_eq!(Polar::ONE.sqrt(), Polar::ONE);
157 }
158
159 #[test]
160 fn abs() {
161 for z in random_samples::<Polar>() {
162 assert_eq!(z.abs_sq(), z.abs * z.abs);
163 }
164 assert_eq!(Polar::ONE.abs, 1.0);
165 assert_eq!(Polar::I.abs, 1.0);
166 assert_eq!(Polar::NEG_ONE.abs, 1.0);
167 assert_eq!(Polar::NEG_I.abs, 1.0);
168 }
169
170 #[test]
171 fn conjugate() {
172 for z in random_samples::<Polar>() {
173 assert_eq!(z.conjugate().re(), z.re());
174 assert_eq!(z.conjugate().im(), -z.im());
175 assert_eq!(z.conjugate().conjugate(), z);
176 }
177 assert_ulps_eq!(Polar::ONE.conjugate().normalize(), Polar::ONE);
178 assert_ulps_eq!(Polar::I.conjugate().normalize(), Polar::NEG_I);
179 assert_ulps_eq!(Polar::NEG_ONE.conjugate().normalize(), Polar::NEG_ONE);
180 assert_ulps_eq!(Polar::NEG_I.conjugate().normalize(), Polar::I);
181 }
182
183 #[test]
184 fn arg() {
185 assert_eq!(Polar::ONE.arg, 0.0);
186 assert_eq!(Polar::I.arg, FRAC_PI_2);
187 assert_eq!(Polar::NEG_ONE.arg, PI);
188 assert_eq!(Polar::NEG_I.arg, -FRAC_PI_2);
189 }
190
191 #[test]
192 fn exp() {
193 for z in random_samples::<Polar>() {
194 assert_eq!(z.exp().abs, z.re().exp());
195 assert_eq!(z.exp().arg, z.im());
196 assert_ulps_eq!(z.exp().ln(), z.to_rectangular());
197 }
198 assert_ulps_eq!(Polar::ONE.exp(), Polar::new(E, 0.0));
199 assert_ulps_eq!(Polar::I.exp(), Polar::new(1.0, 1.0));
200 assert_ulps_eq!(Polar::NEG_ONE.exp(), Polar::new(E.recip(), 0.0));
201 assert_ulps_eq!(Polar::NEG_I.exp(), Polar::new(1.0, -1.0));
202 }
203
204 #[test]
205 fn exp2() {
206 for z in random_samples::<Polar>() {
207 assert_eq!(z.exp2().abs, z.re().exp2());
208 assert_eq!(z.exp2().arg, z.im() * LN_2);
209 assert_ulps_eq!(z.exp2().log2(), z.to_rectangular());
210 }
211 assert_eq!(Polar::ONE.exp2(), Polar::new(2.0, 0.0));
212 assert_ulps_eq!(Polar::I.exp2(), Polar::new(1.0, LN_2));
213 assert_ulps_eq!(Polar::NEG_ONE.exp2(), Polar::new(0.5, 0.0));
214 assert_ulps_eq!(Polar::NEG_I.exp2(), Polar::new(1.0, -LN_2));
215 }
216
217 #[test]
218 fn log() {
219 for z in random_samples::<Polar>() {
220 assert_eq!(z.ln().re, z.abs.ln());
221 assert_eq!(z.ln().im, z.arg);
222 assert_ulps_eq!(z.ln().exp(), z);
223 }
224 assert_eq!(Polar::ONE.ln(), Rectangular::ZERO);
225 assert_eq!(Polar::I.ln(), Rectangular::I * FRAC_PI_2);
226 assert_eq!(Polar::NEG_ONE.ln(), Rectangular::I * PI);
227 assert_eq!(Polar::NEG_I.ln(), Rectangular::I * -FRAC_PI_2);
228
229 assert_ulps_eq!(Polar::new(E, 0.0).ln(), Rectangular::ONE);
230 assert_ulps_eq!(Polar::new(2.0, 0.0).log2(), Rectangular::ONE);
231 assert_ulps_eq!(Polar::new(10.0, 0.0).log10(), Rectangular::ONE);
232 }
233
234 #[test]
235 fn powi() {
236 for z in random_samples::<Polar>() {
237 assert_eq!(z.powi(0), Polar::ONE);
238 assert_eq!(z.powi(1), z);
239 for n in random_samples::<i32>() {
240 assert_eq!(z.powi(n).abs, z.abs.powi(n));
241 assert_eq!(z.powi(n).arg, z.arg * n as FT);
242 }
243 }
244 for n in random_samples::<i32>() {
245 assert_eq!(Polar::ZERO.powi(n.abs()), Polar::ZERO);
246 assert_eq!(Polar::ONE.powi(n), Polar::ONE);
247 }
248 }
249
250 #[test]
251 fn powf() {
252 for z in random_samples::<Polar>() {
253 assert_eq!(z.powf(0.0), Polar::ONE);
254 assert_eq!(z.powf(1.0), z);
255 for n in random_samples::<i32>() {
256 let x = n as FT * 0.01;
257 assert_eq!(z.powf(x).abs, z.abs.powf(x));
258 assert_eq!(z.powf(x).arg, z.arg * x);
259 }
260 }
261 for n in random_samples::<i32>() {
262 let x = n as FT * 0.01;
263 assert_eq!(Polar::ZERO.powf(x.abs()), Polar::ZERO);
264 assert_eq!(Polar::ONE.powf(x), Polar::ONE);
265 }
266 }
267
268 #[test]
269 fn normalize() {
270 for z in random_samples::<Polar>() {
271 for n in uniform_samples::<i32>(-99, 99) {
272 let w = Polar::new(z.abs, z.arg + n as FT * TAU);
273 assert_ulps_eq!(z, w.normalize(), epsilon = 2000.0 * FT::EPSILON);
274
275 assert_ulps_eq!(
276 Polar::new(-z.abs, z.arg).normalize(),
277 Polar::new(z.abs, z.arg + PI).normalize(),
278 epsilon = 2000.0 * FT::EPSILON
279 );
280 }
281 }
282 }
283}