num_complex/
pow.rs

1use super::Complex;
2
3use core::ops::Neg;
4#[cfg(any(feature = "std", feature = "libm"))]
5use num_traits::Float;
6use num_traits::{Num, One, Pow};
7
8macro_rules! pow_impl {
9    ($U:ty, $S:ty) => {
10        impl<'a, T: Clone + Num> Pow<$U> for &'a Complex<T> {
11            type Output = Complex<T>;
12
13            #[inline]
14            fn pow(self, mut exp: $U) -> Self::Output {
15                if exp == 0 {
16                    return Complex::one();
17                }
18                let mut base = self.clone();
19
20                while exp & 1 == 0 {
21                    base = base.clone() * base;
22                    exp >>= 1;
23                }
24
25                if exp == 1 {
26                    return base;
27                }
28
29                let mut acc = base.clone();
30                while exp > 1 {
31                    exp >>= 1;
32                    base = base.clone() * base;
33                    if exp & 1 == 1 {
34                        acc = acc * base.clone();
35                    }
36                }
37                acc
38            }
39        }
40
41        impl<'a, 'b, T: Clone + Num> Pow<&'b $U> for &'a Complex<T> {
42            type Output = Complex<T>;
43
44            #[inline]
45            fn pow(self, exp: &$U) -> Self::Output {
46                self.pow(*exp)
47            }
48        }
49
50        impl<'a, T: Clone + Num + Neg<Output = T>> Pow<$S> for &'a Complex<T> {
51            type Output = Complex<T>;
52
53            #[inline]
54            fn pow(self, exp: $S) -> Self::Output {
55                if exp < 0 {
56                    Pow::pow(&self.inv(), exp.wrapping_neg() as $U)
57                } else {
58                    Pow::pow(self, exp as $U)
59                }
60            }
61        }
62
63        impl<'a, 'b, T: Clone + Num + Neg<Output = T>> Pow<&'b $S> for &'a Complex<T> {
64            type Output = Complex<T>;
65
66            #[inline]
67            fn pow(self, exp: &$S) -> Self::Output {
68                self.pow(*exp)
69            }
70        }
71    };
72}
73
74pow_impl!(u8, i8);
75pow_impl!(u16, i16);
76pow_impl!(u32, i32);
77pow_impl!(u64, i64);
78pow_impl!(usize, isize);
79pow_impl!(u128, i128);
80
81// Note: we can't add `impl<T: Float> Pow<T> for Complex<T>` because new blanket impls are a
82// breaking change.  Someone could already have their own `F` and `impl Pow<F> for Complex<F>`
83// which would conflict.  We can't even do this in a new semantic version, because we have to
84// gate it on the "std" feature, and features can't add breaking changes either.
85
86macro_rules! powf_impl {
87    ($F:ty) => {
88        #[cfg(any(feature = "std", feature = "libm"))]
89        impl<'a, T: Float> Pow<$F> for &'a Complex<T>
90        where
91            $F: Into<T>,
92        {
93            type Output = Complex<T>;
94
95            #[inline]
96            fn pow(self, exp: $F) -> Self::Output {
97                self.powf(exp.into())
98            }
99        }
100
101        #[cfg(any(feature = "std", feature = "libm"))]
102        impl<'a, 'b, T: Float> Pow<&'b $F> for &'a Complex<T>
103        where
104            $F: Into<T>,
105        {
106            type Output = Complex<T>;
107
108            #[inline]
109            fn pow(self, &exp: &$F) -> Self::Output {
110                self.powf(exp.into())
111            }
112        }
113
114        #[cfg(any(feature = "std", feature = "libm"))]
115        impl<T: Float> Pow<$F> for Complex<T>
116        where
117            $F: Into<T>,
118        {
119            type Output = Complex<T>;
120
121            #[inline]
122            fn pow(self, exp: $F) -> Self::Output {
123                self.powf(exp.into())
124            }
125        }
126
127        #[cfg(any(feature = "std", feature = "libm"))]
128        impl<'b, T: Float> Pow<&'b $F> for Complex<T>
129        where
130            $F: Into<T>,
131        {
132            type Output = Complex<T>;
133
134            #[inline]
135            fn pow(self, &exp: &$F) -> Self::Output {
136                self.powf(exp.into())
137            }
138        }
139    };
140}
141
142powf_impl!(f32);
143powf_impl!(f64);
144
145// These blanket impls are OK, because both the target type and the trait parameter would be
146// foreign to anyone else trying to implement something that would overlap, raising E0117.
147
148#[cfg(any(feature = "std", feature = "libm"))]
149impl<'a, T: Float> Pow<Complex<T>> for &'a Complex<T> {
150    type Output = Complex<T>;
151
152    #[inline]
153    fn pow(self, exp: Complex<T>) -> Self::Output {
154        self.powc(exp)
155    }
156}
157
158#[cfg(any(feature = "std", feature = "libm"))]
159impl<'a, 'b, T: Float> Pow<&'b Complex<T>> for &'a Complex<T> {
160    type Output = Complex<T>;
161
162    #[inline]
163    fn pow(self, &exp: &'b Complex<T>) -> Self::Output {
164        self.powc(exp)
165    }
166}
167
168#[cfg(any(feature = "std", feature = "libm"))]
169impl<T: Float> Pow<Complex<T>> for Complex<T> {
170    type Output = Complex<T>;
171
172    #[inline]
173    fn pow(self, exp: Complex<T>) -> Self::Output {
174        self.powc(exp)
175    }
176}
177
178#[cfg(any(feature = "std", feature = "libm"))]
179impl<'b, T: Float> Pow<&'b Complex<T>> for Complex<T> {
180    type Output = Complex<T>;
181
182    #[inline]
183    fn pow(self, &exp: &'b Complex<T>) -> Self::Output {
184        self.powc(exp)
185    }
186}