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);