Skip to main content

a/math/complex/
mod.rs

1//! Complex numbers: a [`Complex<T>`] is `re + im·i` with parts of the [`Float`] type `T`, `f32` or
2//! `f64`.
3//!
4//! They add with `+` and `+=`, subtract with `-` and `-=`, multiply with `*` and `*=` and divide
5//! with `/` and `/=`, each operand owned or borrowed, and take a float of their own type as an
6//! operand on either side. They negate with `-`, compare with `==`, add up with `Sum` and multiply
7//! with `Product`, and are written as `1+2i` by `Display`.
8//!
9//! [`Complex::abs`] and [`Complex::arg`] give the polar form, [`Complex::from_polar`] builds a
10//! number from it, and [`Complex::conj`], [`Complex::norm_sqr`] and [`Complex::recip`] the rest
11//! of the arithmetic. [`Complex::exp`], [`Complex::ln`], [`Complex::sqrt`], [`Complex::powi`],
12//! [`Complex::powf`] and [`Complex::powc`] are the principal values, with the branch cut of the
13//! logarithm and the square root along the negative real axis, where the sign of a zero imaginary
14//! part picks the side, as in C99's `<complex.h>`.
15
16mod float;
17mod ops;
18
19pub use float::Float;
20
21use core::fmt;
22
23/// The complex number `re + im·i`.
24///
25/// # Examples
26///
27/// ```
28/// use a::math::complex::Complex;
29///
30/// let z = Complex::new(3.0, 4.0);
31/// assert_eq!(z.abs(), 5.0);
32/// assert_eq!(z * z.conj(), Complex::new(25.0, 0.0));
33/// assert_eq!(Complex::new(-4.0, 0.0).sqrt(), Complex::new(0.0, 2.0));
34/// assert_eq!(format!("{}", z - 2.0 * Complex::I), "3+2i");
35/// ```
36#[derive(Clone, Copy, Debug, Default, PartialEq)]
37#[repr(C)]
38pub struct Complex<T> {
39    /// The real part.
40    pub re: T,
41    /// The imaginary part.
42    pub im: T,
43}
44
45impl<T> Complex<T> {
46    /// The number `re + im·i`.
47    #[inline]
48    pub const fn new(re: T, im: T) -> Self {
49        Complex { re, im }
50    }
51}
52
53impl<T: Float> Complex<T> {
54    /// Zero.
55    pub const ZERO: Self = Complex::new(T::ZERO, T::ZERO);
56    /// One.
57    pub const ONE: Self = Complex::new(T::ONE, T::ZERO);
58    /// The imaginary unit `i`.
59    pub const I: Self = Complex::new(T::ZERO, T::ONE);
60
61    /// The number with the absolute value `r` and the argument `theta`: `r·e^(i·theta)`.
62    #[inline]
63    pub fn from_polar(r: T, theta: T) -> Self {
64        let (sin, cos) = theta.sin_cos();
65        Complex::new(r * cos, r * sin)
66    }
67
68    /// The absolute value and the argument, as [`abs`](Self::abs) and [`arg`](Self::arg) give
69    /// them.
70    #[inline]
71    pub fn to_polar(self) -> (T, T) {
72        (self.abs(), self.arg())
73    }
74
75    /// The complex conjugate, `re - im·i`.
76    #[inline]
77    pub fn conj(self) -> Self {
78        Complex::new(self.re, -self.im)
79    }
80
81    /// The absolute value `√(re² + im²)`, without an overflow or underflow in the squares.
82    #[inline]
83    pub fn abs(self) -> T {
84        self.re.hypot(self.im)
85    }
86
87    /// The square of the absolute value, `re² + im²`: cheaper than `abs`, but it overflows and
88    /// underflows where the squares do.
89    #[inline]
90    pub fn norm_sqr(self) -> T {
91        self.re * self.re + self.im * self.im
92    }
93
94    /// The argument, the angle from the positive real axis, in `(-π, π]`; `-π` for a negative
95    /// real number with a negative zero imaginary part.
96    #[inline]
97    pub fn arg(self) -> T {
98        self.im.atan2(self.re)
99    }
100
101    /// `1 / self`.
102    #[inline]
103    pub fn recip(self) -> Self {
104        Self::ONE / self
105    }
106
107    /// Whether both parts are finite.
108    #[inline]
109    pub fn is_finite(self) -> bool {
110        self.re.is_finite() && self.im.is_finite()
111    }
112
113    /// Whether either part is NaN.
114    #[inline]
115    pub fn is_nan(self) -> bool {
116        self.re.is_nan() || self.im.is_nan()
117    }
118
119    /// `e^self`: `e^re·(cos im + i·sin im)`. A real number stays real, with the sign of its zero
120    /// imaginary part.
121    pub fn exp(self) -> Self {
122        let r = self.re.exp();
123        if self.im == T::ZERO {
124            return Complex::new(r, self.im);
125        }
126        let (sin, cos) = self.im.sin_cos();
127        if r.is_infinite() && self.re.is_finite() {
128            // `e^re` overflows where `e^re·cos` may not, as for `exp(710 + i·π/4)`: the
129            // trigonometric factor between two halves of the exponential.
130            let h = (self.re * T::HALF).exp();
131            return Complex::new(h * cos * h, h * sin * h);
132        }
133        Complex::new(r * cos, r * sin)
134    }
135
136    /// The principal natural logarithm, `ln |self| + i·arg(self)`, whose imaginary part is in
137    /// `(-π, π]`. The logarithm of zero is `-∞`. Near the unit circle the real part is
138    /// `ln(1 + (|self|² - 1)) / 2`, so that it keeps its digits where `ln |self|` is small; where
139    /// `|self|` overflows, or is subnormal, it is `ln(big) + ln(1 + (small/big)²) / 2` of the
140    /// larger and the smaller part, so that `ln(MAX + MAX·i)` is finite.
141    pub fn ln(self) -> Self {
142        let (a, b) = (self.re.abs(), self.im.abs());
143        let (big, small) = if a >= b { (a, b) } else { (b, a) };
144        let re = if big > T::HALF && big < T::TWO {
145            ((big - T::ONE) * (big + T::ONE) + small * small).ln_1p() * T::HALF
146        } else {
147            let m = self.abs();
148            if m.is_finite() && m >= T::MIN_POSITIVE {
149                m.ln()
150            } else {
151                Self::ln_of_extreme(m, big, small)
152            }
153        };
154        Complex::new(re, self.arg())
155    }
156
157    /// `ln |z|` from its absolute value `m` and its larger and smaller part, where `m` overflows
158    /// or is subnormal: `ln(big) + ln(1 + (small/big)²) / 2`. Zero, infinities and NaNs as
159    /// `ln m` gives them.
160    #[cold]
161    #[inline(never)]
162    fn ln_of_extreme(m: T, big: T, small: T) -> T {
163        if big == T::ZERO || !big.is_finite() || !small.is_finite() {
164            return m.ln();
165        }
166        let r = small / big;
167        big.ln() + (r * r).ln_1p() * T::HALF
168    }
169
170    /// The principal square root, whose real part is not negative, by Kahan's method, which
171    /// neither overflows nor cancels: for `re ≥ 0`, `t = √((re + |self|) / 2)` and the root
172    /// `t + i·im / (2t)`, and the other way round for `re < 0`. Infinities and NaNs give what
173    /// C99's `csqrt` gives.
174    pub fn sqrt(self) -> Self {
175        let (re, im) = (self.re, self.im);
176        if re == T::ZERO && im == T::ZERO {
177            return Complex::new(T::ZERO, im);
178        }
179        if im.is_infinite() {
180            return Complex::new(T::INFINITY, im);
181        }
182        if re.is_infinite() {
183            let zero_or_nan = if im.is_nan() {
184                im
185            } else {
186                T::ZERO.copysign(im)
187            };
188            return if re > T::ZERO {
189                Complex::new(re, zero_or_nan)
190            } else {
191                Complex::new(zero_or_nan.abs(), T::INFINITY.copysign(im))
192            };
193        }
194        if re.is_nan() || im.is_nan() {
195            return Complex::new(T::NAN, T::NAN);
196        }
197        let big = re.abs().max(im.abs());
198        if big < T::from_f64(4.0) * T::MIN_POSITIVE {
199            // Near the subnormals: scaled up by 2^64, exactly, and the root back by 2^32.
200            let up = T::from_f64(18_446_744_073_709_551_616.0);
201            return (self * up).sqrt() / T::from_f64(4_294_967_296.0);
202        }
203        if big > T::MAX / T::from_f64(4.0) {
204            return (self * T::from_f64(0.25)).sqrt() * T::TWO;
205        }
206        let t = ((re.abs() + self.abs()) * T::HALF).sqrt();
207        if re >= T::ZERO {
208            Complex::new(t, im / (T::TWO * t))
209        } else {
210            Complex::new(im.abs() / (T::TWO * t), t.copysign(im))
211        }
212    }
213
214    /// `self` to the integer power `n`, by repeated squaring: exact as long as the products are.
215    /// A negative power is the power of the reciprocal, and `0^0` is 1.
216    pub fn powi(self, n: i32) -> Self {
217        let mut base = if n < 0 { self.recip() } else { self };
218        let mut n = n.unsigned_abs();
219        let mut r = Self::ONE;
220        while n > 0 {
221            if n & 1 == 1 {
222                r *= base;
223            }
224            n >>= 1;
225            if n > 0 {
226                base *= base;
227            }
228        }
229        r
230    }
231
232    /// The principal value of `self` to the real power `x`: `e^(x·ln self)`, with `0^x = 0` for
233    /// `x ≠ 0` and `0^0 = 1`.
234    pub fn powf(self, x: T) -> Self {
235        if self.re == T::ZERO && self.im == T::ZERO {
236            return if x == T::ZERO { Self::ONE } else { Self::ZERO };
237        }
238        (self.ln() * x).exp()
239    }
240
241    /// The principal value of `self` to the complex power `w`: `e^(w·ln self)`, with `0^w = 0`
242    /// for `w ≠ 0` and `0^0 = 1`.
243    pub fn powc(self, w: Self) -> Self {
244        if self.re == T::ZERO && self.im == T::ZERO {
245            return if w == Self::ZERO {
246                Self::ONE
247            } else {
248                Self::ZERO
249            };
250        }
251        (self.ln() * w).exp()
252    }
253}
254
255impl<T: Float> From<T> for Complex<T> {
256    /// The real number `re + 0·i`.
257    #[inline]
258    fn from(re: T) -> Self {
259        Complex::new(re, T::ZERO)
260    }
261}
262
263impl<T: Float> fmt::Display for Complex<T> {
264    /// Writes `re+imi` or `re-imi`, each part as `Display` writes the float, with the precision
265    /// given: `1.5-2i`, or `1.50-2.00i` with `{:.2}`.
266    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267        let sign = if self.im.is_sign_negative() { '-' } else { '+' };
268        match f.precision() {
269            Some(p) => write!(f, "{:.*}{}{:.*}i", p, self.re, sign, p, self.im.abs()),
270            None => write!(f, "{}{}{}i", self.re, sign, self.im.abs()),
271        }
272    }
273}