Skip to main content

core/num/
complex.rs

1use crate::num::imp::libm::complex::*;
2use crate::ops::{Add, Div, Mul, Neg, Sub};
3
4/// A [complex number], represented in rectangular form.
5///
6/// # Basic operations
7///
8/// A `Complex<T>` supports addition, subtraction, and negation when `T` does. The conjugation
9/// requires that `T` supports negation.
10///
11/// ```
12/// #![feature(complex_numbers)]
13///
14/// use std::num::Complex;
15///
16/// let x = Complex { re: 5.0, im: 9.0 };
17/// let y = Complex::new(2.0, 3.0);
18///
19/// // Scalar addition and subtraction operate on the real component.
20/// assert_eq!(x + 1.0, Complex::new(6.0, 9.0));
21/// assert_eq!(x - 1.0, Complex::new(4.0, 9.0));
22///
23/// // Complex addition and subtraction operate on each component separately.
24/// assert_eq!(x + y, Complex::new(7.0, 12.0));
25/// assert_eq!(x - y, Complex::new(3.0, 6.0));
26///
27/// // Negation occurs on both components.
28/// // Geometrically this is a rotation by 180 degrees.
29/// assert_eq!(-x, Complex::new(-5.0, -9.0));
30///
31/// // The conjugate negates only the imaginary component.
32/// // Geometrically this is a reflection across the real axis.
33/// assert_eq!(x.conjugate(), Complex::new(5.0, -9.0));
34/// ```
35///
36/// # Complex multiplication and division of floating points
37///
38/// Multiplication and division follow the textbook formulas, except that they attempt to
39/// correct for overflow of intermediate steps of the calculation.
40///
41/// This behavior mirrors the C standard, although it does not specify exactly when the
42/// output should be corrected. Hence, the exact output may vary from platform to platform.
43///
44/// ```
45/// #![feature(complex_numbers)]
46///
47/// use std::num::Complex;
48///
49/// assert_eq!(Complex::new(1.0, 2.0) * Complex::new(3.0, 4.0), Complex::new(-5.0, 10.0));
50/// assert_eq!(Complex::new(2.0, 11.0) / Complex::new(2.0, 1.0), Complex::new(3.0, 4.0));
51///
52/// // The textbook algorithm would return NaN + NaNi for these inputs.
53/// assert_eq!(
54///     Complex::new(1.0, 0.0) * Complex::new(f64::INFINITY, f64::INFINITY),
55///     Complex::new(f64::INFINITY, f64::INFINITY)
56/// );
57/// assert_eq!(
58///     Complex::new(1.0, 1.0) / Complex::new(f64::INFINITY, 0.0),
59///     Complex::new(0.0, 0.0)
60/// );
61/// ```
62///
63/// # FFI compatibility
64///
65/// The following types are guaranteed to fully match the platform's `_Complex` in terms of layout and ABI:
66///
67/// - `Complex<`[`c_float`]`>`
68/// - `Complex<`[`c_double`]`>`
69///
70/// For any other `Complex<T>` ABI compatibility is not guaranteed.
71///
72/// [complex number]: https://en.wikipedia.org/wiki/Complex_number
73/// [`c_float`]: crate::ffi::c_float
74/// [`c_double`]: crate::ffi::c_double
75#[derive(Clone, Copy, Debug, PartialEq, Eq)]
76#[unstable(feature = "complex_numbers", issue = "154023")]
77#[repr(C)]
78#[lang = "complex"]
79pub struct Complex<T> {
80    /// The real component.
81    pub re: T,
82    /// The imaginary component.
83    pub im: T,
84}
85
86#[unstable(feature = "complex_numbers", issue = "154023")]
87impl<T> Complex<T> {
88    /// Create a new complex number from a real and imaginary component.
89    #[must_use]
90    pub const fn new(re: T, im: T) -> Complex<T> {
91        Complex { re, im }
92    }
93}
94
95#[unstable(feature = "complex_numbers", issue = "154023")]
96impl<T: Default> Default for Complex<T> {
97    fn default() -> Self {
98        Self { re: Default::default(), im: Default::default() }
99    }
100}
101
102#[unstable(feature = "complex_numbers", issue = "154023")]
103impl<T> Complex<T>
104where
105    T: Neg<Output = T>,
106{
107    /// The complex conjugate of a complex number.
108    ///
109    /// The conjugate of `a + bi` is `a - bi`: the imaginary component is negated.
110    /// Geometrically, this is a reflection across the real axis.
111    ///
112    /// ```
113    /// #![feature(complex_numbers)]
114    ///
115    /// use std::num::Complex;
116    ///
117    /// assert_eq!(Complex::new(3.0, 2.0).conjugate(), Complex::new(3.0, -2.0));
118    /// assert_eq!(Complex::new(-3.0, -2.0).conjugate(), Complex::new(-3.0, 2.0));
119    /// ```
120    #[must_use]
121    pub fn conjugate(self) -> Self {
122        Complex { re: self.re, im: -self.im }
123    }
124}
125
126#[unstable(feature = "complex_numbers", issue = "154023")]
127impl<T: Neg> Neg for Complex<T> {
128    type Output = Complex<T::Output>;
129
130    /// Negate a complex number.
131    ///
132    /// The negation of `a + bi` is `-a - bi`: both components are negated.
133    /// Geometrically this is a rotation of 180°.
134    ///
135    /// ```
136    /// #![feature(complex_numbers)]
137    ///
138    /// use std::num::Complex;
139    ///
140    /// assert_eq!(-Complex::new(3.0, 2.0), Complex::new(-3.0, -2.0));
141    /// ```
142    fn neg(self) -> Self::Output {
143        Complex::new(-self.re, -self.im)
144    }
145}
146
147#[unstable(feature = "complex_numbers", issue = "154023")]
148impl<T: Add> Add<Self> for Complex<T> {
149    type Output = Complex<T::Output>;
150
151    /// Complex addition operates on each component separately.
152    ///
153    /// ```
154    /// #![feature(complex_numbers)]
155    ///
156    /// use std::num::Complex;
157    ///
158    /// assert_eq!(Complex::new(2.0, 3.0) + Complex::new(5.0, 9.0), Complex::new(7.0, 12.0));
159    /// ```
160    fn add(self, rhs: Self) -> Self::Output {
161        Complex::new(self.re + rhs.re, self.im + rhs.im)
162    }
163}
164
165#[unstable(feature = "complex_numbers", issue = "154023")]
166impl<T: Add<Output = T>> Add<T> for Complex<T> {
167    type Output = Complex<T::Output>;
168
169    /// Scalar addition operates only on the real component.
170    ///
171    /// ```
172    /// #![feature(complex_numbers)]
173    ///
174    /// use std::num::Complex;
175    ///
176    /// assert_eq!(Complex::new(2.0, 3.0) + 10.0, Complex::new(12.0, 3.0));
177    /// ```
178    fn add(self, rhs: T) -> Self::Output {
179        Complex::new(self.re + rhs, self.im)
180    }
181}
182
183#[unstable(feature = "complex_numbers", issue = "154023")]
184impl<T: Sub> Sub<Self> for Complex<T> {
185    type Output = Complex<T::Output>;
186
187    /// Complex subtraction operates on each component separately.
188    ///
189    /// ```
190    /// #![feature(complex_numbers)]
191    ///
192    /// use std::num::Complex;
193    ///
194    /// assert_eq!(Complex::new(2.0, 3.0) - Complex::new(5.0, 9.0), Complex::new(-3.0, -6.0));
195    /// ```
196    fn sub(self, rhs: Self) -> Self::Output {
197        Complex::new(self.re - rhs.re, self.im - rhs.im)
198    }
199}
200
201#[unstable(feature = "complex_numbers", issue = "154023")]
202impl<T: Sub<Output = T>> Sub<T> for Complex<T> {
203    type Output = Complex<T::Output>;
204
205    /// Scalar subtraction operates only on the real component.
206    ///
207    /// ```
208    /// #![feature(complex_numbers)]
209    ///
210    /// use std::num::Complex;
211    ///
212    /// assert_eq!(Complex::new(2.0, 3.0) - 10.0, Complex::new(-8.0, 3.0));
213    /// ```
214    fn sub(self, rhs: T) -> Self::Output {
215        Complex::new(self.re - rhs, self.im)
216    }
217}
218
219macro_rules! impl_complex_mul_div {
220    ($ty:ty, $mul:ident, $div:ident) => {
221        #[unstable(feature = "complex_numbers", issue = "154023")]
222        impl Mul for Complex<$ty> {
223            type Output = Self;
224
225            #[inline]
226            fn mul(self, rhs: Self) -> Self::Output {
227                let Complex { re: a, im: b } = self;
228                let Complex { re: c, im: d } = rhs;
229
230                let ac = a * c;
231                let bd = b * d;
232                let ad = a * d;
233                let bc = b * c;
234
235                let z = Complex::new(ac - bd, ad + bc);
236
237                // Only call the libcall when both components are NaN.
238                //
239                // The naive algorithm would return NaN + NaNi for an input like
240                // (1 + 0i) * (inf + infi). The libcall instead returns inf + infi.
241                //
242                // We duplicate the fast path here so that it can be inlined. We use a libcall
243                // for the NaN correction to reduce the size of `core`.
244                if z.re.is_nan() && z.im.is_nan() {
245                    crate::hint::cold_path();
246                    $mul(a, b, c, d)
247                } else {
248                    z
249                }
250            }
251        }
252
253        #[unstable(feature = "complex_numbers", issue = "154023")]
254        impl Div for Complex<$ty> {
255            type Output = Self;
256
257            #[inline]
258            fn div(self, rhs: Self) -> Self::Output {
259                $div(self.re, self.im, rhs.re, rhs.im)
260            }
261        }
262    };
263}
264
265impl_complex_mul_div!(f16, __rust_mulhc3, __rust_divhc3);
266impl_complex_mul_div!(f32, __mulsc3, __divsc3);
267impl_complex_mul_div!(f64, __muldc3, __divdc3);
268impl_complex_mul_div!(f128, __rust_multc3, __rust_divtc3);