From f06f5c548ef012b79e6ea6f59c0c273e1b25d030 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 12 Jul 2017 14:37:50 -0700 Subject: [PATCH] complex: implement real ops directly It's more efficient to implement these without creating an intermediate complex value -- at the least, we don't have to rely on the compiler optimizing out zero-ops. --- complex/src/lib.rs | 101 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 24 deletions(-) diff --git a/complex/src/lib.rs b/complex/src/lib.rs index cb605a2..a0b2dec 100644 --- a/complex/src/lib.rs +++ b/complex/src/lib.rs @@ -587,38 +587,91 @@ macro_rules! real_arithmetic { } )* ); - (@implement $imp:ident::$method:ident for $($real:ident),*) => ( - impl $imp for Complex { - type Output = Complex; - - #[inline] - fn $method(self, other: T) -> Complex { - self.$method(Complex::from(other)) - } - } - $( - impl $imp> for $real { - type Output = Complex<$real>; - - #[inline] - fn $method(self, other: Complex<$real>) -> Complex<$real> { - Complex::from(self).$method(other) - } - } - )* - ); ($($real:ident),*) => ( real_arithmetic!(@forward Add::add for $($real),*); real_arithmetic!(@forward Sub::sub for $($real),*); real_arithmetic!(@forward Mul::mul for $($real),*); real_arithmetic!(@forward Div::div for $($real),*); - real_arithmetic!(@implement Add::add for $($real),*); - real_arithmetic!(@implement Sub::sub for $($real),*); - real_arithmetic!(@implement Mul::mul for $($real),*); - real_arithmetic!(@implement Div::div for $($real),*); + + $( + impl Add> for $real { + type Output = Complex<$real>; + + #[inline] + fn add(self, other: Complex<$real>) -> Complex<$real> { + Complex::new(self + other.re, other.im) + } + } + + impl Sub> for $real { + type Output = Complex<$real>; + + #[inline] + fn sub(self, other: Complex<$real>) -> Complex<$real> { + Complex::new(self - other.re, $real::zero() - other.im) + } + } + + impl Mul> for $real { + type Output = Complex<$real>; + + #[inline] + fn mul(self, other: Complex<$real>) -> Complex<$real> { + Complex::new(self * other.re, self * other.im) + } + } + + impl Div> for $real { + type Output = Complex<$real>; + + #[inline] + fn div(self, other: Complex<$real>) -> Complex<$real> { + // a / (c + i d) == [a * (c - i d)] / (c*c + d*d) + let norm_sqr = other.norm_sqr(); + Complex::new(self * other.re / norm_sqr.clone(), + $real::zero() - self * other.im / norm_sqr) + } + } + )* ); } +impl Add for Complex { + type Output = Complex; + + #[inline] + fn add(self, other: T) -> Complex { + Complex::new(self.re + other, self.im) + } +} + +impl Sub for Complex { + type Output = Complex; + + #[inline] + fn sub(self, other: T) -> Complex { + Complex::new(self.re - other, self.im) + } +} + +impl Mul for Complex { + type Output = Complex; + + #[inline] + fn mul(self, other: T) -> Complex { + Complex::new(self.re * other.clone(), self.im * other) + } +} + +impl Div for Complex { + type Output = Complex; + + #[inline] + fn div(self, other: T) -> Complex { + Complex::new(self.re / other.clone(), self.im / other) + } +} + real_arithmetic!(usize, u8, u16, u32, u64, isize, i8, i16, i32, i64, f32, f64); /* constants */