Skip to content

Commit 24fcc15

Browse files
committed
Added powc, powf, log and expf methods for complex numbers
1 parent 0861fb4 commit 24fcc15

File tree

1 file changed

+99
-3
lines changed

1 file changed

+99
-3
lines changed

complex/src/lib.rs

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ impl<T: Clone + Float> Complex<T> {
120120
#[inline]
121121
pub fn exp(&self) -> Complex<T> {
122122
// formula: e^(a + bi) = e^a (cos(b) + i*sin(b))
123-
Complex::new(self.im.cos(), self.im.sin()).scale(self.re.exp())
123+
// = from_polar(e^a, b)
124+
Complex::from_polar(&self.re.exp(), &self.im)
124125
}
125126

126127
/// Computes the principal value of natural logarithm of `self`.
@@ -133,7 +134,8 @@ impl<T: Clone + Float> Complex<T> {
133134
#[inline]
134135
pub fn ln(&self) -> Complex<T> {
135136
// formula: ln(z) = ln|z| + i*arg(z)
136-
Complex::new(self.norm().ln(), self.arg())
137+
let (r, theta) = self.to_polar();
138+
Complex::new(r.ln(), theta)
137139
}
138140

139141
/// Computes the principal value of the square root of `self`.
@@ -150,6 +152,53 @@ impl<T: Clone + Float> Complex<T> {
150152
let (r, theta) = self.to_polar();
151153
Complex::from_polar(&(r.sqrt()), &(theta/two))
152154
}
155+
156+
/// Raises `self` to a floating point power.
157+
#[inline]
158+
pub fn powf(&self, exp: T) -> Complex<T> {
159+
// formula: x^y = (ρ e^(i θ))^y = ρ^y e^(i θ y)
160+
// = from_polar(ρ^y, θ y)
161+
let (r, theta) = self.to_polar();
162+
Complex::from_polar(&r.powf(exp), &(theta*exp))
163+
}
164+
165+
/// Returns the logarithm of `self` with respect to an arbitrary base.
166+
#[inline]
167+
pub fn log(&self, base: T) -> Complex<T> {
168+
// formula: log_y(x) = log_y(ρ e^(i θ))
169+
// = log_y(ρ) + log_y(e^(i θ)) = log_y(ρ) + ln(e^(i θ)) / ln(y)
170+
// = log_y(ρ) + i θ / ln(y)
171+
let (r, theta) = self.to_polar();
172+
Complex::new(r.log(base), theta / base.ln())
173+
}
174+
175+
/// Raises `self` to a complex power.
176+
#[inline]
177+
pub fn powc(&self, exp: Complex<T>) -> Complex<T> {
178+
// formula: x^y = (a + i b)^(c + i d)
179+
// = (ρ e^(i θ))^c (ρ e^(i θ))^(i d)
180+
// where ρ=|x| and θ=arg(x)
181+
// = ρ^c e^(−d θ) e^(i c θ) ρ^(i d)
182+
// = p^c e^(−d θ) (cos(c θ)
183+
// + i sin(c θ)) (cos(d ln(ρ)) + i sin(d ln(ρ)))
184+
// = p^c e^(−d θ) (
185+
// cos(c θ) cos(d ln(ρ)) − sin(c θ) sin(d ln(ρ))
186+
// + i(cos(c θ) sin(d ln(ρ)) + sin(c θ) cos(d ln(ρ))))
187+
// = p^c e^(−d θ) (cos(c θ + d ln(ρ)) + i sin(c θ + d ln(ρ)))
188+
// = from_polar(p^c e^(−d θ), c θ + d ln(ρ))
189+
let (r, theta) = self.to_polar();
190+
Complex::from_polar(
191+
&(r.powf(exp.re) * (-exp.im * theta).exp()),
192+
&(exp.re * theta + exp.im * r.ln()))
193+
}
194+
195+
/// Raises a floating point number to the complex power `self`.
196+
#[inline]
197+
pub fn expf(&self, base: T) -> Complex<T> {
198+
// formula: x^(a+bi) = x^a x^bi = x^a e^(b ln(x) i)
199+
// = from_polar(x^a, b ln(x))
200+
Complex::from_polar(&base.powf(self.re), &(self.im * base.ln()))
201+
}
153202

154203
/// Computes the sine of `self`.
155204
#[inline]
@@ -716,8 +765,12 @@ mod test {
716765
}
717766

718767
fn close(a: Complex64, b: Complex64) -> bool {
768+
close_to_tol(a, b, 1e-10)
769+
}
770+
771+
fn close_to_tol(a: Complex64, b: Complex64, tol: f64) -> bool {
719772
// returns true if a and b are reasonably close
720-
(a == b) || (a-b).norm() < 1e-10
773+
(a == b) || (a-b).norm() < tol
721774
}
722775

723776
#[test]
@@ -748,6 +801,49 @@ mod test {
748801
assert!(-f64::consts::PI <= c.ln().arg() && c.ln().arg() <= f64::consts::PI);
749802
}
750803
}
804+
805+
#[test]
806+
fn test_powc()
807+
{
808+
let a = Complex::new(2.0, -3.0);
809+
let b = Complex::new(3.0, 0.0);
810+
assert!(close(a.powc(b), a.powf(b.re)));
811+
assert!(close(b.powc(a), a.expf(b.re)));
812+
let c = Complex::new(1.0 / 3.0, 0.1);
813+
assert!(close_to_tol(a.powc(c), Complex::new(1.65826, -0.33502), 1e-5));
814+
}
815+
816+
#[test]
817+
fn test_powf()
818+
{
819+
let c = Complex::new(2.0, -1.0);
820+
let r = c.powf(3.5);
821+
assert!(close_to_tol(r, Complex::new(-0.8684746, -16.695934), 1e-5));
822+
}
823+
824+
#[test]
825+
fn test_log()
826+
{
827+
let c = Complex::new(2.0, -1.0);
828+
let r = c.log(10.0);
829+
assert!(close_to_tol(r, Complex::new(0.349485, -0.20135958), 1e-5));
830+
}
831+
832+
#[test]
833+
fn test_some_expf_cases()
834+
{
835+
let c = Complex::new(2.0, -1.0);
836+
let r = c.expf(10.0);
837+
assert!(close_to_tol(r, Complex::new(-66.82015, -74.39803), 1e-5));
838+
839+
let c = Complex::new(5.0, -2.0);
840+
let r = c.expf(3.4);
841+
assert!(close_to_tol(r, Complex::new(-349.25, -290.63), 1e-2));
842+
843+
let c = Complex::new(-1.5, 2.0 / 3.0);
844+
let r = c.expf(1.0 / 3.0);
845+
assert!(close_to_tol(r, Complex::new(3.8637, -3.4745), 1e-2));
846+
}
751847

752848
#[test]
753849
fn test_sqrt() {

0 commit comments

Comments
 (0)