Skip to main content

a/math/complex/
ops.rs

1//! The operators of complex numbers.
2
3use super::{Complex, Float};
4use core::iter::{Product, Sum};
5use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
6
7impl<T: Float> Complex<T> {
8    #[inline]
9    fn plus(a: Self, b: Self) -> Self {
10        Complex::new(a.re + b.re, a.im + b.im)
11    }
12
13    #[inline]
14    fn plus_real(a: Self, b: T) -> Self {
15        Complex::new(a.re + b, a.im)
16    }
17
18    #[inline]
19    fn real_plus(a: T, b: Self) -> Self {
20        Complex::new(a + b.re, b.im)
21    }
22
23    #[inline]
24    fn minus(a: Self, b: Self) -> Self {
25        Complex::new(a.re - b.re, a.im - b.im)
26    }
27
28    #[inline]
29    fn minus_real(a: Self, b: T) -> Self {
30        Complex::new(a.re - b, a.im)
31    }
32
33    #[inline]
34    fn real_minus(a: T, b: Self) -> Self {
35        Complex::new(a - b.re, -b.im)
36    }
37
38    #[inline]
39    fn times(a: Self, b: Self) -> Self {
40        Complex::new(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re)
41    }
42
43    #[inline]
44    fn times_real(a: Self, b: T) -> Self {
45        Complex::new(a.re * b, a.im * b)
46    }
47
48    #[inline]
49    fn real_times(a: T, b: Self) -> Self {
50        Complex::new(a * b.re, a * b.im)
51    }
52
53    /// `a / b` by Smith's method: the larger part `p` of `b` divides the smaller `q`, so that
54    /// nothing overflows where the quotient doesn't. The two cases differ only in which parts
55    /// play which role and in a sign, chosen by selects rather than a branch, which random
56    /// operands would mispredict half the time. A zero `b` takes `r = 0`, which leaves `a.re / 0`
57    /// and `a.im / 0`, infinities or NaNs as for floats, by a select too.
58    ///
59    /// At the ends of the range, as LAPACK's `ladiv` (Baudin and Smith), all four parts are
60    /// scaled by one power of two, which leaves the quotient as it was: halved when one of them
61    /// is at least half the largest float, as the sums are at most twice the largest part, so
62    /// that `(1e308 + 1e308·i) / (1e308 + 1e308·i)` is 1, not a NaN from `∞ / ∞`; and scaled
63    /// up by `8/ε²` when the parts of either operand are all below `4·MIN/ε`, so that Smith's
64    /// products keep their digits and `(u + u·i) / (u + 2u·i)` for the smallest subnormal `u`
65    /// is `0.6 - 0.2i`. Where that makes the other operand overflow or vanish, the quotient
66    /// overflows or underflows anyway. Where `r` itself falls below the normal range, the
67    /// products with it are taken as `(y·q)/p`, so that `1e300 / (1e100 + 1e-250·i)` keeps its
68    /// imaginary part `-1e-150`. All of it took a quotient from 1.1 ns to 2.0 on an Apple M4
69    /// Max; separate factors for the two operands took 2.3, and the rare cases out of line in a
70    /// function of their own 4.1, its call alone keeping the loop from overlapping quotients.
71    #[inline]
72    fn over(a: Self, b: Self) -> Self {
73        let zero = T::ZERO;
74        let (aa, ab, ba, bb) = (a.re.abs(), a.im.abs(), b.re.abs(), b.im.abs());
75        let limit = T::MAX * T::HALF;
76        let tiny = T::MIN_POSITIVE * T::from_f64(4.0) / T::EPSILON;
77        let big = (aa >= limit) | (ab >= limit) | (ba >= limit) | (bb >= limit);
78        let small = ((aa <= tiny) & (ab <= tiny)) | ((ba <= tiny) & (bb <= tiny));
79        let s = if big {
80            T::HALF
81        } else if small {
82            T::from_f64(8.0) / (T::EPSILON * T::EPSILON)
83        } else {
84            T::ONE
85        };
86        let (ar, ai, br, bi) = (a.re * s, a.im * s, b.re * s, b.im * s);
87        let swap = br.abs() < bi.abs();
88        let (p, q) = if swap { (bi, br) } else { (br, bi) };
89        let (x, y) = if swap { (ai, ar) } else { (ar, ai) };
90        let r = if p == zero { zero } else { q / p };
91        let d = p + q * r;
92        let (yr, xr) = if r.abs() < T::MIN_POSITIVE && q != zero && p != zero {
93            ((y * q) / p, (x * q) / p)
94        } else {
95            (y * r, x * r)
96        };
97        let im = (y - xr) / d;
98        Complex::new((x + yr) / d, if swap { -im } else { im })
99    }
100
101    #[inline]
102    fn over_real(a: Self, b: T) -> Self {
103        Complex::new(a.re / b, a.im / b)
104    }
105
106    #[inline]
107    fn real_over(a: T, b: Self) -> Self {
108        Complex::over(Complex::from(a), b)
109    }
110}
111
112/// An operator between two complex numbers, and between a complex number and a float of its
113/// type on the right, owned or borrowed, with its assignments.
114macro_rules! operators {
115    ($op:ident, $method:ident, $assign:ident, $assign_method:ident, $both:ident, $real:ident) => {
116        impl<T: Float> $op for Complex<T> {
117            type Output = Self;
118            #[inline]
119            fn $method(self, rhs: Self) -> Self {
120                Complex::$both(self, rhs)
121            }
122        }
123        impl<T: Float> $op<&Complex<T>> for Complex<T> {
124            type Output = Self;
125            #[inline]
126            fn $method(self, rhs: &Self) -> Self {
127                Complex::$both(self, *rhs)
128            }
129        }
130        impl<T: Float> $op<Complex<T>> for &Complex<T> {
131            type Output = Complex<T>;
132            #[inline]
133            fn $method(self, rhs: Complex<T>) -> Complex<T> {
134                Complex::$both(*self, rhs)
135            }
136        }
137        impl<T: Float> $op<&Complex<T>> for &Complex<T> {
138            type Output = Complex<T>;
139            #[inline]
140            fn $method(self, rhs: &Complex<T>) -> Complex<T> {
141                Complex::$both(*self, *rhs)
142            }
143        }
144        impl<T: Float> $op<T> for Complex<T> {
145            type Output = Self;
146            #[inline]
147            fn $method(self, rhs: T) -> Self {
148                Complex::$real(self, rhs)
149            }
150        }
151        impl<T: Float> $op<&T> for Complex<T> {
152            type Output = Self;
153            #[inline]
154            fn $method(self, rhs: &T) -> Self {
155                Complex::$real(self, *rhs)
156            }
157        }
158        impl<T: Float> $op<T> for &Complex<T> {
159            type Output = Complex<T>;
160            #[inline]
161            fn $method(self, rhs: T) -> Complex<T> {
162                Complex::$real(*self, rhs)
163            }
164        }
165        impl<T: Float> $op<&T> for &Complex<T> {
166            type Output = Complex<T>;
167            #[inline]
168            fn $method(self, rhs: &T) -> Complex<T> {
169                Complex::$real(*self, *rhs)
170            }
171        }
172        impl<T: Float> $assign for Complex<T> {
173            #[inline]
174            fn $assign_method(&mut self, rhs: Self) {
175                *self = Complex::$both(*self, rhs);
176            }
177        }
178        impl<T: Float> $assign<&Complex<T>> for Complex<T> {
179            #[inline]
180            fn $assign_method(&mut self, rhs: &Self) {
181                *self = Complex::$both(*self, *rhs);
182            }
183        }
184        impl<T: Float> $assign<T> for Complex<T> {
185            #[inline]
186            fn $assign_method(&mut self, rhs: T) {
187                *self = Complex::$real(*self, rhs);
188            }
189        }
190        impl<T: Float> $assign<&T> for Complex<T> {
191            #[inline]
192            fn $assign_method(&mut self, rhs: &T) {
193                *self = Complex::$real(*self, *rhs);
194            }
195        }
196    };
197}
198
199operators!(Add, add, AddAssign, add_assign, plus, plus_real);
200operators!(Sub, sub, SubAssign, sub_assign, minus, minus_real);
201operators!(Mul, mul, MulAssign, mul_assign, times, times_real);
202operators!(Div, div, DivAssign, div_assign, over, over_real);
203
204/// An operator with a float on the left of a complex number of its type, which the orphan rule
205/// leaves to one implementation for each float type.
206macro_rules! left {
207    ($t:ident, $op:ident, $method:ident, $left:ident) => {
208        impl $op<Complex<$t>> for $t {
209            type Output = Complex<$t>;
210            #[inline]
211            fn $method(self, rhs: Complex<$t>) -> Complex<$t> {
212                Complex::$left(self, rhs)
213            }
214        }
215        impl $op<&Complex<$t>> for $t {
216            type Output = Complex<$t>;
217            #[inline]
218            fn $method(self, rhs: &Complex<$t>) -> Complex<$t> {
219                Complex::$left(self, *rhs)
220            }
221        }
222        impl $op<Complex<$t>> for &$t {
223            type Output = Complex<$t>;
224            #[inline]
225            fn $method(self, rhs: Complex<$t>) -> Complex<$t> {
226                Complex::$left(*self, rhs)
227            }
228        }
229        impl $op<&Complex<$t>> for &$t {
230            type Output = Complex<$t>;
231            #[inline]
232            fn $method(self, rhs: &Complex<$t>) -> Complex<$t> {
233                Complex::$left(*self, *rhs)
234            }
235        }
236    };
237}
238
239macro_rules! lefts {
240    ($t:ident) => {
241        left!($t, Add, add, real_plus);
242        left!($t, Sub, sub, real_minus);
243        left!($t, Mul, mul, real_times);
244        left!($t, Div, div, real_over);
245    };
246}
247
248lefts!(f32);
249lefts!(f64);
250
251impl<T: Float> Neg for Complex<T> {
252    type Output = Self;
253    #[inline]
254    fn neg(self) -> Self {
255        Complex::new(-self.re, -self.im)
256    }
257}
258
259impl<T: Float> Neg for &Complex<T> {
260    type Output = Complex<T>;
261    #[inline]
262    fn neg(self) -> Complex<T> {
263        -*self
264    }
265}
266
267impl<T: Float> Sum for Complex<T> {
268    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
269        iter.fold(Self::ZERO, |s, z| s + z)
270    }
271}
272
273impl<'a, T: Float> Sum<&'a Complex<T>> for Complex<T> {
274    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
275        iter.fold(Self::ZERO, |s, z| s + z)
276    }
277}
278
279impl<T: Float> Product for Complex<T> {
280    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
281        iter.fold(Self::ONE, |p, z| p * z)
282    }
283}
284
285impl<'a, T: Float> Product<&'a Complex<T>> for Complex<T> {
286    fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
287        iter.fold(Self::ONE, |p, z| p * z)
288    }
289}