From 19c31b6b1afef7cad83275b2e73d27e5c44ed2a1 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 11 Jun 2013 11:37:33 +1000 Subject: [PATCH] extra: implement .norm(), and Polar conversion functions for complex numbers. Also, convert complex to use Clone, rather than Copy. Fixes #5734 and #5735. --- src/libextra/num/complex.rs | 77 ++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/src/libextra/num/complex.rs b/src/libextra/num/complex.rs index 10bfe9409daa4..1bb364f3a1c3f 100644 --- a/src/libextra/num/complex.rs +++ b/src/libextra/num/complex.rs @@ -35,7 +35,7 @@ pub type Complex = Cmplx; pub type Complex32 = Cmplx; pub type Complex64 = Cmplx; -impl Cmplx { +impl Cmplx { /// Create a new Cmplx #[inline] pub fn new(re: T, im: T) -> Cmplx { @@ -55,7 +55,7 @@ impl Cmplx { /// Returns the complex conjugate. i.e. `re - i im` #[inline] pub fn conj(&self) -> Cmplx { - Cmplx::new(self.re, -self.im) + Cmplx::new(self.re.clone(), -self.im) } @@ -80,42 +80,71 @@ impl Cmplx { } } +#[cfg(not(stage0))] // Fixed by #4228 +impl Cmplx { + /// Calculate |self| + #[inline(always)] + pub fn norm(&self) -> T { + self.re.hypot(&self.im) + } +} + +#[cfg(not(stage0))] // Fixed by #4228 +impl Cmplx { + /// Calculate the principal Arg of self. + #[inline(always)] + pub fn arg(&self) -> T { + self.im.atan2(&self.re) + } + /// Convert to polar form (r, theta), such that `self = r * exp(i + /// * theta)` + #[inline] + pub fn to_polar(&self) -> (T, T) { + (self.norm(), self.arg()) + } + /// Convert a polar representation into a complex number. + #[inline] + pub fn from_polar(r: &T, theta: &T) -> Cmplx { + Cmplx::new(r * theta.cos(), r * theta.sin()) + } +} + /* arithmetic */ // (a + i b) + (c + i d) == (a + c) + i (b + d) -impl Add, Cmplx> for Cmplx { +impl Add, Cmplx> for Cmplx { #[inline] fn add(&self, other: &Cmplx) -> Cmplx { Cmplx::new(self.re + other.re, self.im + other.im) } } // (a + i b) - (c + i d) == (a - c) + i (b - d) -impl Sub, Cmplx> for Cmplx { +impl Sub, Cmplx> for Cmplx { #[inline] fn sub(&self, other: &Cmplx) -> Cmplx { Cmplx::new(self.re - other.re, self.im - other.im) } } // (a + i b) * (c + i d) == (a*c - b*d) + i (a*d + b*c) -impl Mul, Cmplx> for Cmplx { +impl Mul, Cmplx> for Cmplx { #[inline] fn mul(&self, other: &Cmplx) -> Cmplx { Cmplx::new(self.re*other.re - self.im*other.im, - self.re*other.im + self.im*other.re) + self.re*other.im + self.im*other.re) } } // (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d) // == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)] -impl Div, Cmplx> for Cmplx { +impl Div, Cmplx> for Cmplx { #[inline] fn div(&self, other: &Cmplx) -> Cmplx { let norm_sqr = other.norm_sqr(); Cmplx::new((self.re*other.re + self.im*other.im) / norm_sqr, - (self.im*other.re - self.re*other.im) / norm_sqr) + (self.im*other.re - self.re*other.im) / norm_sqr) } } -impl Neg> for Cmplx { +impl Neg> for Cmplx { #[inline] fn neg(&self) -> Cmplx { Cmplx::new(-self.re, -self.im) @@ -123,7 +152,7 @@ impl Neg> for Cmplx { } /* constants */ -impl Zero for Cmplx { +impl Zero for Cmplx { #[inline] fn zero() -> Cmplx { Cmplx::new(Zero::zero(), Zero::zero()) @@ -131,11 +160,11 @@ impl Zero for Cmplx { #[inline] fn is_zero(&self) -> bool { - *self == Zero::zero() + self.re.is_zero() && self.im.is_zero() } } -impl One for Cmplx { +impl One for Cmplx { #[inline] fn one() -> Cmplx { Cmplx::new(One::one(), Zero::zero()) @@ -166,7 +195,7 @@ impl ToStrRadix for Cmplx { #[cfg(test)] mod test { use super::*; - use core::num::{Zero,One}; + use core::num::{Zero,One,Real}; pub static _0_0i : Complex = Cmplx { re: 0f, im: 0f }; pub static _1_0i : Complex = Cmplx { re: 1f, im: 0f }; @@ -193,9 +222,10 @@ mod test { } #[test] - fn test_norm_sqr() { + fn test_norm() { fn test(c: Complex, ns: float) { assert_eq!(c.norm_sqr(), ns); + assert_eq!(c.norm(), ns.sqrt()) } test(_0_0i, 0f); test(_1_0i, 1f); @@ -235,6 +265,25 @@ mod test { _0_0i.inv(); } + #[test] + fn test_arg() { + fn test(c: Complex, arg: float) { + assert!(c.arg().approx_eq(&arg)) + } + test(_1_0i, 0f); + test(_1_1i, 0.25f * Real::pi()); + test(_neg1_1i, 0.75f * Real::pi()); + test(_05_05i, 0.25f * Real::pi()); + } + + #[test] + fn test_polar_conv() { + fn test(c: Complex) { + let (r, theta) = c.to_polar(); + assert!((c - Cmplx::from_polar(&r, &theta)).norm() < 1e-6); + } + for all_consts.each |&c| { test(c); } + } mod arith { use super::*;