Skip to content

Commit 7af251e

Browse files
committed
Add Complex::powi and assorted Pow impls
1 parent 813e021 commit 7af251e

File tree

2 files changed

+140
-2
lines changed

2 files changed

+140
-2
lines changed

src/lib.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@ use core::str::FromStr;
3838
#[cfg(feature = "std")]
3939
use std::error::Error;
4040

41-
use traits::{Inv, MulAdd, Num, One, Signed, Zero};
41+
use traits::{Inv, MulAdd, Num, One, Pow, Signed, Zero};
4242

4343
#[cfg(feature = "std")]
4444
use traits::float::Float;
4545
use traits::float::FloatCore;
4646

4747
mod cast;
48+
mod pow;
49+
4850
#[cfg(feature = "rand")]
4951
mod crand;
5052
#[cfg(feature = "rand")]
@@ -121,6 +123,12 @@ impl<T: Clone + Num> Complex<T> {
121123
pub fn unscale(&self, t: T) -> Self {
122124
Self::new(self.re.clone() / t.clone(), self.im.clone() / t)
123125
}
126+
127+
/// Raises `self` to an unsigned integer power.
128+
#[inline]
129+
pub fn powu(&self, exp: u32) -> Self {
130+
Pow::pow(self, exp)
131+
}
124132
}
125133

126134
impl<T: Clone + Num + Neg<Output = T>> Complex<T> {
@@ -139,6 +147,12 @@ impl<T: Clone + Num + Neg<Output = T>> Complex<T> {
139147
-self.im.clone() / norm_sqr,
140148
)
141149
}
150+
151+
/// Raises `self` to a signed integer power.
152+
#[inline]
153+
pub fn powi(&self, exp: i32) -> Self {
154+
Pow::pow(self, exp)
155+
}
142156
}
143157

144158
impl<T: Clone + Signed> Complex<T> {
@@ -1487,6 +1501,25 @@ mod test {
14871501
assert_eq!(_4_2i.l1_norm(), 6.0);
14881502
}
14891503

1504+
#[test]
1505+
fn test_pow() {
1506+
for c in all_consts.iter() {
1507+
assert_eq!(c.powi(0), _1_0i);
1508+
let mut pos = _1_0i;
1509+
let mut neg = _1_0i;
1510+
for i in 1i32..20 {
1511+
pos *= c;
1512+
assert_eq!(pos, c.powi(i));
1513+
if c.is_zero() {
1514+
assert!(c.powi(-i).is_nan());
1515+
} else {
1516+
neg /= c;
1517+
assert_eq!(neg, c.powi(-i));
1518+
}
1519+
}
1520+
}
1521+
}
1522+
14901523
#[cfg(feature = "std")]
14911524
mod float {
14921525
use super::*;
@@ -1535,7 +1568,11 @@ mod test {
15351568

15361569
fn close_to_tol(a: Complex64, b: Complex64, tol: f64) -> bool {
15371570
// returns true if a and b are reasonably close
1538-
(a == b) || (a - b).norm() < tol
1571+
let close = (a == b) || (a - b).norm() < tol;
1572+
if !close {
1573+
println!("{:?} != {:?}", a, b);
1574+
}
1575+
close
15391576
}
15401577

15411578
#[test]

src/pow.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use super::Complex;
2+
3+
use std::ops::Neg;
4+
use traits::{Float, Num, One, Pow};
5+
6+
macro_rules! pow_impl {
7+
($U:ty, $S:ty) => {
8+
impl<'a, T: Clone + Num> Pow<$U> for &'a Complex<T> {
9+
type Output = Complex<T>;
10+
11+
#[inline]
12+
fn pow(self, mut exp: $U) -> Self::Output {
13+
if exp == 0 {
14+
return Complex::one();
15+
}
16+
let mut base = self.clone();
17+
18+
while exp & 1 == 0 {
19+
base = base.clone() * base;
20+
exp >>= 1;
21+
}
22+
23+
if exp == 1 {
24+
return base;
25+
}
26+
27+
let mut acc = base.clone();
28+
while exp > 1 {
29+
exp >>= 1;
30+
base = base.clone() * base;
31+
if exp & 1 == 1 {
32+
acc = acc * base.clone();
33+
}
34+
}
35+
acc
36+
}
37+
}
38+
39+
impl<'a, 'b, T: Clone + Num> Pow<&'b $U> for &'a Complex<T> {
40+
type Output = Complex<T>;
41+
42+
#[inline]
43+
fn pow(self, exp: &$U) -> Self::Output {
44+
self.pow(*exp)
45+
}
46+
}
47+
48+
impl<'a, T: Clone + Num + Neg<Output = T>> Pow<$S> for &'a Complex<T> {
49+
type Output = Complex<T>;
50+
51+
#[inline]
52+
fn pow(self, exp: $S) -> Self::Output {
53+
if exp < 0 {
54+
Pow::pow(&self.inv(), exp.wrapping_neg() as $U)
55+
} else {
56+
Pow::pow(self, exp as $U)
57+
}
58+
}
59+
}
60+
61+
impl<'a, 'b, T: Clone + Num + Neg<Output = T>> Pow<&'b $S> for &'a Complex<T> {
62+
type Output = Complex<T>;
63+
64+
#[inline]
65+
fn pow(self, exp: &$S) -> Self::Output {
66+
self.pow(*exp)
67+
}
68+
}
69+
};
70+
}
71+
72+
pow_impl!(u8, i8);
73+
pow_impl!(u16, i16);
74+
pow_impl!(u32, i32);
75+
pow_impl!(u64, i64);
76+
pow_impl!(usize, isize);
77+
#[cfg(has_i128)]
78+
pow_impl!(u128, i128);
79+
80+
// Note: the impls above are for `&Complex<T>`, while those below are for `Complex<T>`. This is
81+
// fine since `Float: Copy` anyway, but it's also necessary to avoid conflicting implementations.
82+
// Otherwise rustc would insist that those `Pow<{integer}>` impls could overlap with `Pow<T>` if
83+
// integers ever implement `Float`, though of course we know they won't...
84+
85+
impl<T: Float> Pow<T> for Complex<T> {
86+
type Output = Complex<T>;
87+
88+
#[inline]
89+
fn pow(self, exp: T) -> Self::Output {
90+
self.powf(exp)
91+
}
92+
}
93+
94+
impl<T: Float> Pow<Complex<T>> for Complex<T> {
95+
type Output = Complex<T>;
96+
97+
#[inline]
98+
fn pow(self, exp: Complex<T>) -> Self::Output {
99+
self.powc(exp)
100+
}
101+
}

0 commit comments

Comments
 (0)