complex: forward ops to val-val

Since the Num constraint only requires val-val ops, we ended up cloning
everything in Complex ops when they were forwarded to ref-ref.  By using
val-val, we can reduce how often clones are needed.
This commit is contained in:
Josh Stone 2015-11-16 10:10:59 -08:00
parent b4026b9fec
commit c310e5da8e
1 changed files with 38 additions and 36 deletions

View File

@ -79,12 +79,12 @@ impl<T: Clone + Float> Complex<T> {
/// Calculate |self|
#[inline]
pub fn norm(&self) -> T {
self.re.clone().hypot(self.im.clone())
self.re.hypot(self.im)
}
/// Calculate the principal Arg of self.
#[inline]
pub fn arg(&self) -> T {
self.im.clone().atan2(self.re.clone())
self.im.atan2(self.re)
}
/// Convert to polar form (r, theta), such that `self = r * exp(i
/// * theta)`
@ -102,7 +102,7 @@ impl<T: Clone + Float> Complex<T> {
#[inline]
pub fn exp(&self) -> Complex<T> {
// formula: e^(a + bi) = e^a (cos(b) + i*sin(b))
Complex::new(self.im.clone().cos(), self.im.clone().sin()).scale(self.re.clone().exp())
Complex::new(self.im.cos(), self.im.sin()).scale(self.re.exp())
}
/// Computes the principal value of natural logarithm of `self`.
@ -137,22 +137,22 @@ impl<T: Clone + Float> Complex<T> {
#[inline]
pub fn sin(&self) -> Complex<T> {
// formula: sin(a + bi) = sin(a)cosh(b) + i*cos(a)sinh(b)
Complex::new(self.re.clone().sin() * self.im.clone().cosh(), self.re.clone().cos() * self.im.clone().sinh())
Complex::new(self.re.sin() * self.im.cosh(), self.re.cos() * self.im.sinh())
}
/// Computes the cosine of `self`.
#[inline]
pub fn cos(&self) -> Complex<T> {
// formula: cos(a + bi) = cos(a)cosh(b) - i*sin(a)sinh(b)
Complex::new(self.re.clone().cos() * self.im.clone().cosh(), -self.re.clone().sin() * self.im.clone().sinh())
Complex::new(self.re.cos() * self.im.cosh(), -self.re.sin() * self.im.sinh())
}
/// Computes the tangent of `self`.
#[inline]
pub fn tan(&self) -> Complex<T> {
// formula: tan(a + bi) = (sin(2a) + i*sinh(2b))/(cos(2a) + cosh(2b))
let (two_re, two_im) = (self.re.clone() + self.re.clone(), self.im.clone() + self.im.clone());
Complex::new(two_re.clone().sin(), two_im.clone().sinh()).unscale(two_re.cos() + two_im.cosh())
let (two_re, two_im) = (self.re + self.re, self.im + self.im);
Complex::new(two_re.sin(), two_im.sinh()).unscale(two_re.cos() + two_im.cosh())
}
/// Computes the principal value of the inverse sine of `self`.
@ -212,22 +212,22 @@ impl<T: Clone + Float> Complex<T> {
#[inline]
pub fn sinh(&self) -> Complex<T> {
// formula: sinh(a + bi) = sinh(a)cos(b) + i*cosh(a)sin(b)
Complex::new(self.re.clone().sinh() * self.im.clone().cos(), self.re.clone().cosh() * self.im.clone().sin())
Complex::new(self.re.sinh() * self.im.cos(), self.re.cosh() * self.im.sin())
}
/// Computes the hyperbolic cosine of `self`.
#[inline]
pub fn cosh(&self) -> Complex<T> {
// formula: cosh(a + bi) = cosh(a)cos(b) + i*sinh(a)sin(b)
Complex::new(self.re.clone().cosh() * self.im.clone().cos(), self.re.clone().sinh() * self.im.clone().sin())
Complex::new(self.re.cosh() * self.im.cos(), self.re.sinh() * self.im.sin())
}
/// Computes the hyperbolic tangent of `self`.
#[inline]
pub fn tanh(&self) -> Complex<T> {
// formula: tanh(a + bi) = (sinh(2a) + i*sin(2b))/(cosh(2a) + cos(2b))
let (two_re, two_im) = (self.re.clone() + self.re.clone(), self.im.clone() + self.im.clone());
Complex::new(two_re.clone().sinh(), two_im.clone().sin()).unscale(two_re.cosh() + two_im.cos())
let (two_re, two_im) = (self.re + self.re, self.im + self.im);
Complex::new(two_re.sinh(), two_im.sin()).unscale(two_re.cosh() + two_im.cos())
}
/// Computes the principal value of inverse hyperbolic sine of `self`.
@ -321,14 +321,14 @@ impl<'a, T: Clone + Num> From<&'a T> for Complex<T> {
}
}
macro_rules! forward_val_val_binop {
macro_rules! forward_ref_ref_binop {
(impl $imp:ident, $method:ident) => {
impl<T: Clone + Num> $imp<Complex<T>> for Complex<T> {
impl<'a, 'b, T: Clone + Num> $imp<&'b Complex<T>> for &'a Complex<T> {
type Output = Complex<T>;
#[inline]
fn $method(self, other: Complex<T>) -> Complex<T> {
(&self).$method(&other)
fn $method(self, other: &Complex<T>) -> Complex<T> {
self.clone().$method(other.clone())
}
}
}
@ -341,7 +341,7 @@ macro_rules! forward_ref_val_binop {
#[inline]
fn $method(self, other: Complex<T>) -> Complex<T> {
self.$method(&other)
self.clone().$method(other)
}
}
}
@ -354,7 +354,7 @@ macro_rules! forward_val_ref_binop {
#[inline]
fn $method(self, other: &Complex<T>) -> Complex<T> {
(&self).$method(other)
self.$method(other.clone())
}
}
}
@ -362,7 +362,7 @@ macro_rules! forward_val_ref_binop {
macro_rules! forward_all_binop {
(impl $imp:ident, $method:ident) => {
forward_val_val_binop!(impl $imp, $method);
forward_ref_ref_binop!(impl $imp, $method);
forward_ref_val_binop!(impl $imp, $method);
forward_val_ref_binop!(impl $imp, $method);
};
@ -372,39 +372,38 @@ macro_rules! forward_all_binop {
forward_all_binop!(impl Add, add);
// (a + i b) + (c + i d) == (a + c) + i (b + d)
impl<'a, 'b, T: Clone + Num> Add<&'b Complex<T>> for &'a Complex<T> {
impl<T: Clone + Num> Add<Complex<T>> for Complex<T> {
type Output = Complex<T>;
#[inline]
fn add(self, other: &Complex<T>) -> Complex<T> {
Complex::new(self.re.clone() + other.re.clone(),
self.im.clone() + other.im.clone())
fn add(self, other: Complex<T>) -> Complex<T> {
Complex::new(self.re + other.re, self.im + other.im)
}
}
forward_all_binop!(impl Sub, sub);
// (a + i b) - (c + i d) == (a - c) + i (b - d)
impl<'a, 'b, T: Clone + Num> Sub<&'b Complex<T>> for &'a Complex<T> {
impl<T: Clone + Num> Sub<Complex<T>> for Complex<T> {
type Output = Complex<T>;
#[inline]
fn sub(self, other: &Complex<T>) -> Complex<T> {
Complex::new(self.re.clone() - other.re.clone(),
self.im.clone() - other.im.clone())
fn sub(self, other: Complex<T>) -> Complex<T> {
Complex::new(self.re - other.re, self.im - other.im)
}
}
forward_all_binop!(impl Mul, mul);
// (a + i b) * (c + i d) == (a*c - b*d) + i (a*d + b*c)
impl<'a, 'b, T: Clone + Num> Mul<&'b Complex<T>> for &'a Complex<T> {
impl<T: Clone + Num> Mul<Complex<T>> for Complex<T> {
type Output = Complex<T>;
#[inline]
fn mul(self, other: &Complex<T>) -> Complex<T> {
Complex::new(self.re.clone() * other.re.clone() - self.im.clone() * other.im.clone(),
self.re.clone() * other.im.clone() + self.im.clone() * other.re.clone())
fn mul(self, other: Complex<T>) -> Complex<T> {
let re = self.re.clone() * other.re.clone() - self.im.clone() * other.im.clone();
let im = self.re * other.im + self.im * other.re;
Complex::new(re, im)
}
}
@ -412,14 +411,15 @@ forward_all_binop!(impl Div, div);
// (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<'a, 'b, T: Clone + Num> Div<&'b Complex<T>> for &'a Complex<T> {
impl<T: Clone + Num> Div<Complex<T>> for Complex<T> {
type Output = Complex<T>;
#[inline]
fn div(self, other: &Complex<T>) -> Complex<T> {
fn div(self, other: Complex<T>) -> Complex<T> {
let norm_sqr = other.norm_sqr();
Complex::new((self.re.clone() * other.re.clone() + self.im.clone() * other.im.clone()) / norm_sqr.clone(),
(self.im.clone() * other.re.clone() - self.re.clone() * other.im.clone()) / norm_sqr)
let re = self.re.clone() * other.re.clone() + self.im.clone() * other.im.clone();
let im = self.im * other.re - self.re * other.im;
Complex::new(re / norm_sqr.clone(), im / norm_sqr)
}
}
@ -427,7 +427,9 @@ impl<T: Clone + Num + Neg<Output = T>> Neg for Complex<T> {
type Output = Complex<T>;
#[inline]
fn neg(self) -> Complex<T> { -&self }
fn neg(self) -> Complex<T> {
Complex::new(-self.re, -self.im)
}
}
impl<'a, T: Clone + Num + Neg<Output = T>> Neg for &'a Complex<T> {
@ -435,7 +437,7 @@ impl<'a, T: Clone + Num + Neg<Output = T>> Neg for &'a Complex<T> {
#[inline]
fn neg(self) -> Complex<T> {
Complex::new(-self.re.clone(), -self.im.clone())
-self.clone()
}
}