Skip to main content

abels_complex/complex/
rectangular.rs

1use core::ops::*;
2pub type Complex32 = Complex<f32>;
3pub type Complex64 = Complex<f64>;
4use crate::traits::Number;
5
6use super::ComplexPolar as Polar;
7
8/// Creates a complex number in rectangular form.
9#[inline(always)]
10#[must_use]
11pub const fn complex<FT>(re: FT, im: FT) -> Complex<FT> {
12    Complex::new(re, im)
13}
14
15/// A complex number in rectangular form.
16#[derive(Clone, Copy, PartialEq, Debug, Default)]
17#[repr(C)]
18pub struct Complex<FT> {
19    pub re: FT,
20    pub im: FT,
21}
22impl<FT> Complex<FT> {
23    /// Creates a complex number.
24    pub const fn new(re: FT, im: FT) -> Self {
25        Self { re, im }
26    }
27}
28
29impl<FT: Number> Complex<FT> {
30    pub const ZERO: Self = Self::new(FT::ZERO, FT::ZERO);
31    pub const ONE: Self = Self::new(FT::ONE, FT::ZERO);
32    pub const I: Self = Self::new(FT::ZERO, FT::ONE);
33
34    /// Computes the conjugate.
35    pub fn conjugate(self) -> Self {
36        Self::new(self.re, -self.im)
37    }
38
39    /// Computes the absolute value.
40    pub fn abs(self) -> FT {
41        self.abs_sq().sqrt()
42    }
43
44    pub fn square(mut self) -> Self {
45        let two = FT::ONE + FT::ONE;
46        let re = self.re * self.re - self.im * self.im;
47        self.im = self.re * self.im * two;
48        self.re = re;
49        self
50    }
51
52    /// Computes the squared absolute value.
53    ///
54    /// This is faster than `abs()` as it avoids a square root operation.
55    pub fn abs_sq(self) -> FT {
56        self.re * self.re + self.im * self.im
57    }
58
59    /// Computes the argument in the range `(-π, +π]`.
60    pub fn arg(self) -> FT {
61        self.im.atan2(self.re)
62    }
63
64    /// Computes the reciprocal.
65    pub fn recip(self) -> Self {
66        self.conjugate() / self.abs_sq()
67    }
68
69    /// Convert to polar form.
70    pub fn to_polar(self) -> Polar<FT> {
71        Polar::new(self.abs(), self.arg())
72    }
73
74    /// Computes `e^self` where `e` is the base of the natural logarithm.
75    pub fn exp(self) -> Polar<FT> {
76        Polar::new(self.re.exp(), self.im)
77    }
78
79    /// Computes `2^self`.
80    pub fn exp2(self) -> Polar<FT> {
81        Polar::new(self.re.exp2(), self.im * FT::LN_2())
82    }
83
84    /// Computes `e^self - 1`.
85    ///
86    /// More numerically stable than `self.exp().to_rectangular() - 1` when `self ≈ 0`.
87    pub fn expm1(self) -> Self {
88        let two = FT::ONE + FT::ONE;
89        let (sin, cos) = self.im.sin_cos();
90        Self::new(
91            self.re.exp_m1() * cos - two * (self.im / two).sin().powi(2),
92            self.re.exp() * sin,
93        )
94    }
95
96    /// Computes the principal natural logarithm.
97    pub fn ln(self) -> Self {
98        self.to_polar().ln()
99    }
100
101    /// Computes the principal natural logarithm of `1 + self`.
102    ///
103    /// More numerically stable than `(self + 1).ln()` when `self ≈ 0`.
104    pub fn ln_1p(self) -> Self {
105        let two = FT::ONE + FT::ONE;
106        let re = (two * self.re + self.abs_sq()).ln_1p() / two;
107        let im = (self + FT::ONE).arg();
108        Self::new(re, im)
109    }
110
111    /// Computes the principal logarithm in base 2.
112    pub fn log2(self) -> Self {
113        self.ln() / FT::LN_2()
114    }
115
116    /// Computes the principal logarithm in base 10.
117    pub fn log10(self) -> Self {
118        self.ln() / FT::LN_10()
119    }
120
121    /// Computes the k-th branch of the natural logarithm.
122    ///
123    /// The principal value is `k = 0`. Each increment of `k` adds `2πi`.
124    pub fn ln_branch(self, k: i32) -> Self {
125        self.to_polar().ln_branch(k)
126    }
127
128    /// Computes the k-th branch of the natural logarithm of `1 + self`.
129    ///
130    /// The principal value is `k = 0`. Each increment of `k` adds `2πi`.
131    pub fn ln_1p_branch(self, k: i32) -> Self {
132        let p = self.ln_1p();
133        Self::new(p.re, p.im + FT::TAU() * FT::from_i32(k))
134    }
135
136    /// Computes the k-th branch of the base-2 logarithm.
137    pub fn log2_branch(self, k: i32) -> Self {
138        self.to_polar().log2_branch(k)
139    }
140
141    /// Computes the k-th branch of the base-10 logarithm.
142    pub fn log10_branch(self, k: i32) -> Self {
143        self.to_polar().log10_branch(k)
144    }
145
146    /// Computes the k-th square root.
147    ///
148    /// The principal value is `k = 0`. Only `k = 0` and `k = 1` give distinct values.
149    pub fn sqrt_branch(self, k: i32) -> Polar<FT> {
150        self.to_polar().sqrt_branch(k)
151    }
152
153    /// Computes the k-th value of the n-th root.
154    ///
155    /// The `n` distinct values correspond to `k = 0..n-1`.
156    pub fn nth_root(self, n: i32, k: i32) -> Polar<FT> {
157        self.to_polar().nth_root(n, k)
158    }
159
160    /// Raises `self` to the rational power `p/q`, selecting the k-th branch.
161    ///
162    /// There are `q` distinct values corresponding to `k = 0..q-1`, provided `p/q` is in lowest
163    /// terms. If `p/q` is not reduced, first reduce it to find the true number of distinct values.
164    pub fn pow_rational(self, p: i32, q: i32, k: i32) -> Polar<FT> {
165        self.to_polar().pow_rational(p, q, k)
166    }
167
168    /// Raises `self` to an integer power.
169    pub fn powi(self, n: i32) -> Polar<FT> {
170        self.to_polar().powi(n)
171    }
172
173    /// Raises `self` to a floating point power.
174    pub fn powf(self, x: FT) -> Polar<FT> {
175        self.to_polar().powf(x)
176    }
177
178    /// Computes the principal square root.
179    pub fn sqrt(self) -> Self {
180        let two = FT::ONE + FT::ONE;
181        let abs = self.abs();
182        Self::new(
183            ((abs + self.re) / two).sqrt(),
184            ((abs - self.re) / two).sqrt().copysign(self.im),
185        )
186    }
187
188    /// Computes the euclidian distance between two points.
189    pub fn distance(self, other: Self) -> FT {
190        (self - other).abs()
191    }
192
193    /// Computes the squared euclidian distance between two points.
194    pub fn distance_squared(self, other: Self) -> FT {
195        (self - other).abs_sq()
196    }
197
198    /// Computes the linear interpolation between two points based on the value `t`.
199    pub fn lerp(self, other: Self, t: FT) -> Self {
200        self + (other - self) * t
201    }
202}
203
204impl<FT: Number> Add for Complex<FT> {
205    type Output = Self;
206    fn add(self, other: Self) -> Self::Output {
207        Complex::new(self.re + other.re, self.im + other.im)
208    }
209}
210
211impl<FT: Number> Add<FT> for Complex<FT> {
212    type Output = Self;
213    fn add(self, re: FT) -> Self::Output {
214        Complex::new(self.re + re, self.im)
215    }
216}
217
218impl<FT: Number> AddAssign for Complex<FT> {
219    fn add_assign(&mut self, other: Self) {
220        self.re += other.re;
221        self.im += other.im;
222    }
223}
224
225impl<FT: Number> AddAssign<FT> for Complex<FT> {
226    fn add_assign(&mut self, re: FT) {
227        self.re += re;
228    }
229}
230
231impl<FT: Number> Sub for Complex<FT> {
232    type Output = Self;
233    fn sub(self, other: Self) -> Self::Output {
234        Complex::new(self.re - other.re, self.im - other.im)
235    }
236}
237
238impl<FT: Number> Sub<FT> for Complex<FT> {
239    type Output = Self;
240    fn sub(self, re: FT) -> Self::Output {
241        Complex::new(self.re - re, self.im)
242    }
243}
244
245impl<FT: Number> SubAssign for Complex<FT> {
246    fn sub_assign(&mut self, other: Self) {
247        self.re -= other.re;
248        self.im -= other.im;
249    }
250}
251
252impl<FT: Number> SubAssign<FT> for Complex<FT> {
253    fn sub_assign(&mut self, re: FT) {
254        self.re -= re;
255    }
256}
257
258impl<FT: Number> Mul for Complex<FT> {
259    type Output = Self;
260    fn mul(mut self, other: Self) -> Self {
261        self *= other;
262        self
263    }
264}
265
266impl<FT: Number> Mul<FT> for Complex<FT> {
267    type Output = Self;
268    fn mul(self, re: FT) -> Self {
269        Complex::new(self.re * re, self.im * re)
270    }
271}
272
273impl<FT: Number> MulAssign for Complex<FT> {
274    fn mul_assign(&mut self, other: Self) {
275        let re = self.re * other.re - self.im * other.im;
276        self.im = self.re * other.im + self.im * other.re;
277        self.re = re;
278    }
279}
280
281impl<FT: Number> MulAssign<FT> for Complex<FT> {
282    fn mul_assign(&mut self, re: FT) {
283        self.re *= re;
284        self.im *= re;
285    }
286}
287
288impl<FT: Number> Div for Complex<FT> {
289    type Output = Self;
290    fn div(self, other: Self) -> Self::Output {
291        self * other.recip()
292    }
293}
294
295impl<FT: Number> Div<FT> for Complex<FT> {
296    type Output = Self;
297    fn div(self, re: FT) -> Self::Output {
298        Complex::new(self.re / re, self.im / re)
299    }
300}
301
302impl<FT: Number> DivAssign for Complex<FT> {
303    fn div_assign(&mut self, other: Self) {
304        *self = *self / other;
305    }
306}
307
308impl<FT: Number> DivAssign<FT> for Complex<FT> {
309    fn div_assign(&mut self, re: FT) {
310        self.re /= re;
311        self.im /= re;
312    }
313}
314
315impl<FT: Number> Neg for Complex<FT> {
316    type Output = Self;
317    fn neg(self) -> Self::Output {
318        Self::new(-self.re, -self.im)
319    }
320}
321
322impl<FT: Number> From<FT> for Complex<FT> {
323    fn from(value: FT) -> Self {
324        Self::new(value, FT::ZERO)
325    }
326}
327
328#[cfg(feature = "approx")]
329use approx::{AbsDiffEq, RelativeEq, UlpsEq};
330
331#[cfg(feature = "approx")]
332impl<FT: AbsDiffEq + Copy> AbsDiffEq for Complex<FT>
333where
334    <FT as AbsDiffEq>::Epsilon: Copy,
335{
336    type Epsilon = <FT as AbsDiffEq>::Epsilon;
337    fn default_epsilon() -> Self::Epsilon {
338        FT::default_epsilon()
339    }
340    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
341        FT::abs_diff_eq(&self.re, &other.re, epsilon)
342            && FT::abs_diff_eq(&self.im, &other.im, epsilon)
343    }
344}
345
346#[cfg(feature = "approx")]
347impl<FT: RelativeEq + Copy> RelativeEq for Complex<FT>
348where
349    <FT as AbsDiffEq>::Epsilon: Copy,
350{
351    fn default_max_relative() -> Self::Epsilon {
352        FT::default_max_relative()
353    }
354    fn relative_eq(
355        &self,
356        other: &Self,
357        epsilon: Self::Epsilon,
358        max_relative: Self::Epsilon,
359    ) -> bool {
360        FT::relative_eq(&self.re, &other.re, epsilon, max_relative)
361            && FT::relative_eq(&self.im, &other.im, epsilon, max_relative)
362    }
363}
364
365#[cfg(feature = "approx")]
366impl<FT: UlpsEq + Copy> UlpsEq for Complex<FT>
367where
368    <FT as AbsDiffEq>::Epsilon: Copy,
369{
370    fn default_max_ulps() -> u32 {
371        FT::default_max_ulps()
372    }
373    fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
374        FT::ulps_eq(&self.re, &other.re, epsilon, max_ulps)
375            && FT::ulps_eq(&self.im, &other.im, epsilon, max_ulps)
376    }
377}