Skip to main content

abels_complex/complex/
polar.rs

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/// Creates a complex number in polar form.
10#[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/// A complex number in polar form.
17#[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    /// Creates a complex number.
26    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    /// Computes the conjugate.
36    pub fn conjugate(self) -> Self {
37        Self::new(self.abs, -self.arg)
38    }
39
40    /// Computes the real component.
41    pub fn re(self) -> FT {
42        self.abs * self.arg.cos()
43    }
44
45    /// Computes the imaginary component.
46    pub fn im(self) -> FT {
47        self.abs * self.arg.sin()
48    }
49
50    /// Computes the squared absolute value.
51    pub fn abs_sq(self) -> FT {
52        self.abs * self.abs
53    }
54
55    /// Computes the reciprocal.
56    pub fn recip(self) -> Self {
57        Self::new(self.abs.recip(), -self.arg)
58    }
59
60    /// Computes the principal square root.
61    pub fn sqrt(self) -> Self {
62        let two = FT::ONE + FT::ONE;
63        Self::new(self.abs.sqrt(), self.arg / two)
64    }
65
66    /// Convert to rectangular form.
67    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    /// Computes `e^self` where `e` is the base of the natural logarithm.
73    pub fn exp(self) -> Self {
74        self.to_rectangular().exp()
75    }
76
77    /// Computes `2^self`.
78    pub fn exp2(self) -> Self {
79        self.to_rectangular().exp2()
80    }
81
82    /// Computes `e^self - 1`.
83    ///
84    /// More numerically stable than `self.exp().to_rectangular() - 1` when `self ≈ 0`.
85    pub fn expm1(self) -> Rectangular<FT> {
86        self.to_rectangular().expm1()
87    }
88
89    /// Computes the principal natural logarithm.
90    pub fn ln(self) -> Rectangular<FT> {
91        Rectangular::new(self.abs.ln(), self.arg)
92    }
93
94    /// Computes the principal natural logarithm of `1 + self`.
95    ///
96    /// More numerically stable than `(self + 1).ln()` when `self ≈ 0`.
97    pub fn ln_1p(self) -> Rectangular<FT> {
98        self.to_rectangular().ln_1p()
99    }
100
101    /// Computes the principal logarithm in base 2.
102    pub fn log2(self) -> Rectangular<FT> {
103        self.ln() / FT::LN_2()
104    }
105
106    /// Computes the principal logarithm in base 10.
107    pub fn log10(self) -> Rectangular<FT> {
108        self.ln() / FT::LN_10()
109    }
110
111    /// Computes the k-th branch of the natural logarithm.
112    ///
113    /// The principal value is `k = 0`. Each increment of `k` adds `2πi`.
114    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    /// Computes the k-th branch of the natural logarithm of `1 + self`.
119    ///
120    /// The principal value is `k = 0`. Each increment of `k` adds `2πi`.
121    pub fn ln_1p_branch(self, k: i32) -> Rectangular<FT> {
122        self.to_rectangular().ln_1p_branch(k)
123    }
124
125    /// Computes the k-th branch of the base-2 logarithm.
126    pub fn log2_branch(self, k: i32) -> Rectangular<FT> {
127        self.ln_branch(k) / FT::LN_2()
128    }
129
130    /// Computes the k-th branch of the base-10 logarithm.
131    pub fn log10_branch(self, k: i32) -> Rectangular<FT> {
132        self.ln_branch(k) / FT::LN_10()
133    }
134
135    /// Computes the k-th square root.
136    ///
137    /// The principal value is `k = 0`. Only `k = 0` and `k = 1` give distinct values.
138    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    /// Computes the k-th value of the n-th root.
147    ///
148    /// The `n` distinct values correspond to `k = 0..n-1`.
149    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    /// Raises `self` to the rational power `p/q`, selecting the k-th branch.
157    ///
158    /// There are `q` distinct values corresponding to `k = 0..q-1`, provided `p/q` is in lowest
159    /// terms. If `p/q` is not reduced, first reduce it to find the true number of distinct values.
160    pub fn pow_rational(self, p: i32, q: i32, k: i32) -> Self {
161        self.nth_root(q, k).powi(p)
162    }
163
164    /// Raises `self` to a floating point power.
165    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    /// Raises `self` to an integer power.
173    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    /// Normalizes the absolute value and the argument into the range `[0, ∞)` and `(-π, +π]` respectively.
181    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    /// Returns whether both the absolute value and argument are finite.
199    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}