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.
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6#[unstable(feature = "complex_numbers", issue = "154023")]
7#[repr(C)]
8#[lang = "complex"]
9pub struct Complex<T> {
10    /// The real component.
11    pub re: T,
12    /// The imaginary component.
13    pub im: T,
14}
15
16#[unstable(feature = "complex_numbers", issue = "154023")]
17impl<T> Complex<T> {
18    /// Create a new complex number from a real and imaginary component.
19    #[must_use]
20    pub const fn new(re: T, im: T) -> Complex<T> {
21        Complex { re, im }
22    }
23}
24
25#[unstable(feature = "complex_numbers", issue = "154023")]
26impl<T: Default> Default for Complex<T> {
27    fn default() -> Self {
28        Self { re: Default::default(), im: Default::default() }
29    }
30}
31
32#[unstable(feature = "complex_numbers", issue = "154023")]
33impl<T> Complex<T>
34where
35    T: Neg<Output = T>,
36{
37    /// The complex conjugate of a complex number.
38    ///
39    /// The conjugate of `a + bi` is `a - bi`: the imaginary component is negated.
40    /// Geometrically, this is a reflection across the real axis.
41    #[must_use]
42    pub fn conjugate(self) -> Self {
43        Complex { re: self.re, im: -self.im }
44    }
45}
46
47#[unstable(feature = "complex_numbers", issue = "154023")]
48impl<T: Neg> Neg for Complex<T> {
49    type Output = Complex<T::Output>;
50
51    /// Negate a complex number.
52    ///
53    /// The negation of `a + bi` is `-a - bi`: both components are negated.
54    /// Geometrically this is a rotation of 180°.
55    fn neg(self) -> Self::Output {
56        Complex::new(-self.re, -self.im)
57    }
58}
59
60#[unstable(feature = "complex_numbers", issue = "154023")]
61impl<T: Add> Add<Self> for Complex<T> {
62    type Output = Complex<T::Output>;
63
64    fn add(self, rhs: Self) -> Self::Output {
65        Complex::new(self.re + rhs.re, self.im + rhs.im)
66    }
67}
68
69#[unstable(feature = "complex_numbers", issue = "154023")]
70impl<T: Add<Output = T>> Add<T> for Complex<T> {
71    type Output = Complex<T::Output>;
72
73    fn add(self, rhs: T) -> Self::Output {
74        Complex::new(self.re + rhs, self.im)
75    }
76}
77
78#[unstable(feature = "complex_numbers", issue = "154023")]
79impl<T: Sub> Sub<Self> for Complex<T> {
80    type Output = Complex<T::Output>;
81
82    fn sub(self, rhs: Self) -> Self::Output {
83        Complex::new(self.re - rhs.re, self.im - rhs.im)
84    }
85}
86
87#[unstable(feature = "complex_numbers", issue = "154023")]
88impl<T: Sub<Output = T>> Sub<T> for Complex<T> {
89    type Output = Complex<T::Output>;
90
91    fn sub(self, rhs: T) -> Self::Output {
92        Complex::new(self.re - rhs, self.im)
93    }
94}
95
96macro_rules! impl_complex_mul_div {
97    ($ty:ty, $mul:ident, $div:ident) => {
98        #[unstable(feature = "complex_numbers", issue = "154023")]
99        impl Mul for Complex<$ty> {
100            type Output = Self;
101
102            #[inline]
103            fn mul(self, rhs: Self) -> Self::Output {
104                let Complex { re: a, im: b } = self;
105                let Complex { re: c, im: d } = rhs;
106
107                let ac = a * c;
108                let bd = b * d;
109                let ad = a * d;
110                let bc = b * c;
111
112                let z = Complex::new(ac - bd, ad + bc);
113
114                // Only call the libcall when both components are NaN.
115                //
116                // The naive algorithm would return NaN + NaNi for an input like
117                // (1 + 0i) * (inf + infi). The libcall instead returns inf + infi.
118                //
119                // We duplicate the fast path here so that it can be inlined. We use a libcall
120                // for the NaN correction to reduce the size of `core`.
121                if z.re.is_nan() && z.im.is_nan() {
122                    crate::hint::cold_path();
123                    $mul(a, b, c, d)
124                } else {
125                    z
126                }
127            }
128        }
129
130        #[unstable(feature = "complex_numbers", issue = "154023")]
131        impl Div for Complex<$ty> {
132            type Output = Self;
133
134            #[inline]
135            fn div(self, rhs: Self) -> Self::Output {
136                $div(self.re, self.im, rhs.re, rhs.im)
137            }
138        }
139    };
140}
141
142impl_complex_mul_div!(f16, __rust_mulhc3, __rust_divhc3);
143impl_complex_mul_div!(f32, __mulsc3, __divsc3);
144impl_complex_mul_div!(f64, __muldc3, __divdc3);
145impl_complex_mul_div!(f128, __rust_multc3, __rust_divtc3);