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 the principal natural logarithm.
85    pub fn ln(self) -> Self {
86        self.to_polar().ln()
87    }
88
89    /// Computes the principal natural logarithm of `1 + self`.
90    ///
91    /// More numerically stable than `(self + 1).ln()` when `self ≈ 0`.
92    pub fn ln_1p(self) -> Self {
93        let two = FT::ONE + FT::ONE;
94        let re = (two * self.re + self.abs_sq()).ln_1p() / two;
95        let im = (self + FT::ONE).arg();
96        Self::new(re, im)
97    }
98
99    /// Computes the principal logarithm in base 2.
100    pub fn log2(self) -> Self {
101        self.ln() / FT::LN_2()
102    }
103
104    /// Computes the principal logarithm in base 10.
105    pub fn log10(self) -> Self {
106        self.ln() / FT::LN_10()
107    }
108
109    /// Raises `self` to an integer power.
110    pub fn powi(self, n: i32) -> Polar<FT> {
111        self.to_polar().powi(n)
112    }
113
114    /// Raises `self` to a floating point power.
115    pub fn powf(self, x: FT) -> Polar<FT> {
116        self.to_polar().powf(x)
117    }
118
119    /// Computes the principal square root.
120    pub fn sqrt(self) -> Self {
121        let two = FT::ONE + FT::ONE;
122        let abs = self.abs();
123        Self::new(
124            ((abs + self.re) / two).sqrt(),
125            ((abs - self.re) / two).sqrt().copysign(self.im),
126        )
127    }
128
129    /// Computes the euclidian distance between two points.
130    pub fn distance(self, other: Self) -> FT {
131        (self - other).abs()
132    }
133
134    /// Computes the squared euclidian distance between two points.
135    pub fn distance_squared(self, other: Self) -> FT {
136        (self - other).abs_sq()
137    }
138
139    /// Computes the linear interpolation between two points based on the value `t`.
140    pub fn lerp(self, other: Self, t: FT) -> Self {
141        self + (other - self) * t
142    }
143}
144
145impl<FT: Number> Add for Complex<FT> {
146    type Output = Self;
147    fn add(self, other: Self) -> Self::Output {
148        Complex::new(self.re + other.re, self.im + other.im)
149    }
150}
151
152impl<FT: Number> Add<FT> for Complex<FT> {
153    type Output = Self;
154    fn add(self, re: FT) -> Self::Output {
155        Complex::new(self.re + re, self.im)
156    }
157}
158
159impl<FT: Number> AddAssign for Complex<FT> {
160    fn add_assign(&mut self, other: Self) {
161        self.re += other.re;
162        self.im += other.im;
163    }
164}
165
166impl<FT: Number> AddAssign<FT> for Complex<FT> {
167    fn add_assign(&mut self, re: FT) {
168        self.re += re;
169    }
170}
171
172impl<FT: Number> Sub for Complex<FT> {
173    type Output = Self;
174    fn sub(self, other: Self) -> Self::Output {
175        Complex::new(self.re - other.re, self.im - other.im)
176    }
177}
178
179impl<FT: Number> Sub<FT> for Complex<FT> {
180    type Output = Self;
181    fn sub(self, re: FT) -> Self::Output {
182        Complex::new(self.re - re, self.im)
183    }
184}
185
186impl<FT: Number> SubAssign for Complex<FT> {
187    fn sub_assign(&mut self, other: Self) {
188        self.re -= other.re;
189        self.im -= other.im;
190    }
191}
192
193impl<FT: Number> SubAssign<FT> for Complex<FT> {
194    fn sub_assign(&mut self, re: FT) {
195        self.re -= re;
196    }
197}
198
199impl<FT: Number> Mul for Complex<FT> {
200    type Output = Self;
201    fn mul(mut self, other: Self) -> Self {
202        self *= other;
203        self
204    }
205}
206
207impl<FT: Number> Mul<FT> for Complex<FT> {
208    type Output = Self;
209    fn mul(self, re: FT) -> Self {
210        Complex::new(self.re * re, self.im * re)
211    }
212}
213
214impl<FT: Number> MulAssign for Complex<FT> {
215    fn mul_assign(&mut self, other: Self) {
216        let re = self.re * other.re - self.im * other.im;
217        self.im = self.re * other.im + self.im * other.re;
218        self.re = re;
219    }
220}
221
222impl<FT: Number> MulAssign<FT> for Complex<FT> {
223    fn mul_assign(&mut self, re: FT) {
224        self.re *= re;
225        self.im *= re;
226    }
227}
228
229impl<FT: Number> Div for Complex<FT> {
230    type Output = Self;
231    fn div(self, other: Self) -> Self::Output {
232        self * other.recip()
233    }
234}
235
236impl<FT: Number> Div<FT> for Complex<FT> {
237    type Output = Self;
238    fn div(self, re: FT) -> Self::Output {
239        Complex::new(self.re / re, self.im / re)
240    }
241}
242
243impl<FT: Number> DivAssign for Complex<FT> {
244    fn div_assign(&mut self, other: Self) {
245        *self = *self / other;
246    }
247}
248
249impl<FT: Number> DivAssign<FT> for Complex<FT> {
250    fn div_assign(&mut self, re: FT) {
251        self.re /= re;
252        self.im /= re;
253    }
254}
255
256impl<FT: Number> Neg for Complex<FT> {
257    type Output = Self;
258    fn neg(self) -> Self::Output {
259        Self::new(-self.re, -self.im)
260    }
261}
262
263impl<FT: Number> From<FT> for Complex<FT> {
264    fn from(value: FT) -> Self {
265        Self::new(value, FT::ZERO)
266    }
267}
268
269#[cfg(feature = "approx")]
270use approx::{AbsDiffEq, RelativeEq, UlpsEq};
271
272#[cfg(feature = "approx")]
273impl<FT: AbsDiffEq + Copy> AbsDiffEq for Complex<FT>
274where
275    <FT as AbsDiffEq>::Epsilon: Copy,
276{
277    type Epsilon = <FT as AbsDiffEq>::Epsilon;
278    fn default_epsilon() -> Self::Epsilon {
279        FT::default_epsilon()
280    }
281    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
282        FT::abs_diff_eq(&self.re, &other.re, epsilon)
283            && FT::abs_diff_eq(&self.im, &other.im, epsilon)
284    }
285}
286
287#[cfg(feature = "approx")]
288impl<FT: RelativeEq + Copy> RelativeEq for Complex<FT>
289where
290    <FT as AbsDiffEq>::Epsilon: Copy,
291{
292    fn default_max_relative() -> Self::Epsilon {
293        FT::default_max_relative()
294    }
295    fn relative_eq(
296        &self,
297        other: &Self,
298        epsilon: Self::Epsilon,
299        max_relative: Self::Epsilon,
300    ) -> bool {
301        FT::relative_eq(&self.re, &other.re, epsilon, max_relative)
302            && FT::relative_eq(&self.im, &other.im, epsilon, max_relative)
303    }
304}
305
306#[cfg(feature = "approx")]
307impl<FT: UlpsEq + Copy> UlpsEq for Complex<FT>
308where
309    <FT as AbsDiffEq>::Epsilon: Copy,
310{
311    fn default_max_ulps() -> u32 {
312        FT::default_max_ulps()
313    }
314    fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
315        FT::ulps_eq(&self.re, &other.re, epsilon, max_ulps)
316            && FT::ulps_eq(&self.im, &other.im, epsilon, max_ulps)
317    }
318}