1 use super::Complex;
2 
3 use core::ops::Neg;
4 #[cfg(any(feature = "std", feature = "libm"))]
5 use num_traits::Float;
6 use num_traits::{Num, One, Pow};
7 
8 macro_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 
74 pow_impl!(u8, i8);
75 pow_impl!(u16, i16);
76 pow_impl!(u32, i32);
77 pow_impl!(u64, i64);
78 pow_impl!(usize, isize);
79 pow_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 
86 macro_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 
142 powf_impl!(f32);
143 powf_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"))]
149 impl<'a, T: Float> Pow<Complex<T>> for &'a Complex<T> {
150     type Output = Complex<T>;
151 
152     #[inline]
pow(self, exp: Complex<T>) -> Self::Output153     fn pow(self, exp: Complex<T>) -> Self::Output {
154         self.powc(exp)
155     }
156 }
157 
158 #[cfg(any(feature = "std", feature = "libm"))]
159 impl<'a, 'b, T: Float> Pow<&'b Complex<T>> for &'a Complex<T> {
160     type Output = Complex<T>;
161 
162     #[inline]
pow(self, &exp: &'b Complex<T>) -> Self::Output163     fn pow(self, &exp: &'b Complex<T>) -> Self::Output {
164         self.powc(exp)
165     }
166 }
167 
168 #[cfg(any(feature = "std", feature = "libm"))]
169 impl<T: Float> Pow<Complex<T>> for Complex<T> {
170     type Output = Complex<T>;
171 
172     #[inline]
pow(self, exp: Complex<T>) -> Self::Output173     fn pow(self, exp: Complex<T>) -> Self::Output {
174         self.powc(exp)
175     }
176 }
177 
178 #[cfg(any(feature = "std", feature = "libm"))]
179 impl<'b, T: Float> Pow<&'b Complex<T>> for Complex<T> {
180     type Output = Complex<T>;
181 
182     #[inline]
pow(self, &exp: &'b Complex<T>) -> Self::Output183     fn pow(self, &exp: &'b Complex<T>) -> Self::Output {
184         self.powc(exp)
185     }
186 }
187