Auto merge of #125 - IvanUkhov:real-arithmetic, r=cuviper

Implement arithmetic with real for complex

Hello,

It might be handy to be able to perform basic arithmetic operations in expressions mixing complex numbers and numeric primitives; see #116. I would be grateful for any feedback, especially regarding the subsets of primitives for which certain operations are implemented.

Regards,
Ivan
This commit is contained in:
Homu 2015-11-12 03:03:06 +09:00
commit 879f2c868e
1 changed files with 132 additions and 3 deletions

View File

@ -307,6 +307,20 @@ impl<T: Clone + Float> Complex<T> {
} }
} }
impl<T: Clone + Num> From<T> for Complex<T> {
#[inline]
fn from(re: T) -> Complex<T> {
Complex { re: re, im: T::zero() }
}
}
impl<'a, T: Clone + Num> From<&'a T> for Complex<T> {
#[inline]
fn from(re: &T) -> Complex<T> {
From::from(re.clone())
}
}
macro_rules! forward_val_val_binop { macro_rules! forward_val_val_binop {
(impl $imp:ident, $method:ident) => { (impl $imp:ident, $method:ident) => {
impl<T: Clone + Num> $imp<Complex<T>> for Complex<T> { impl<T: Clone + Num> $imp<Complex<T>> for Complex<T> {
@ -425,6 +439,93 @@ impl<'a, T: Clone + Num + Neg<Output = T>> Neg for &'a Complex<T> {
} }
} }
macro_rules! real_arithmetic {
(@forward $imp:ident::$method:ident for $($real:ident),*) => (
impl<'a, T: Clone + Num> $imp<&'a T> for Complex<T> {
type Output = Complex<T>;
#[inline]
fn $method(self, other: &T) -> Complex<T> {
self.$method(other.clone())
}
}
impl<'a, T: Clone + Num> $imp<T> for &'a Complex<T> {
type Output = Complex<T>;
#[inline]
fn $method(self, other: T) -> Complex<T> {
self.clone().$method(other)
}
}
impl<'a, 'b, T: Clone + Num> $imp<&'a T> for &'b Complex<T> {
type Output = Complex<T>;
#[inline]
fn $method(self, other: &T) -> Complex<T> {
self.clone().$method(other.clone())
}
}
$(
impl<'a> $imp<&'a Complex<$real>> for $real {
type Output = Complex<$real>;
#[inline]
fn $method(self, other: &Complex<$real>) -> Complex<$real> {
self.$method(other.clone())
}
}
impl<'a> $imp<Complex<$real>> for &'a $real {
type Output = Complex<$real>;
#[inline]
fn $method(self, other: Complex<$real>) -> Complex<$real> {
self.clone().$method(other)
}
}
impl<'a, 'b> $imp<&'a Complex<$real>> for &'b $real {
type Output = Complex<$real>;
#[inline]
fn $method(self, other: &Complex<$real>) -> Complex<$real> {
self.clone().$method(other.clone())
}
}
)*
);
(@implement $imp:ident::$method:ident for $($real:ident),*) => (
impl<T: Clone + Num> $imp<T> for Complex<T> {
type Output = Complex<T>;
#[inline]
fn $method(self, other: T) -> Complex<T> {
self.$method(Complex::from(other))
}
}
$(
impl $imp<Complex<$real>> 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),*);
);
}
real_arithmetic!(usize, u8, u16, u32, u64, isize, i8, i16, i32, i64, f32, f64);
/* constants */ /* constants */
impl<T: Clone + Num> Zero for Complex<T> { impl<T: Clone + Num> Zero for Complex<T> {
#[inline] #[inline]
@ -856,7 +957,7 @@ mod test {
} }
} }
mod arith { mod complex_arithmetic {
use super::{_0_0i, _1_0i, _1_1i, _0_1i, _neg1_1i, _05_05i, all_consts}; use super::{_0_0i, _1_0i, _1_1i, _0_1i, _neg1_1i, _05_05i, all_consts};
use Zero; use Zero;
@ -898,6 +999,7 @@ mod test {
assert_eq!(_1_0i * c, c); assert_eq!(_1_0i * c, c);
} }
} }
#[test] #[test]
fn test_div() { fn test_div() {
assert_eq!(_neg1_1i / _0_1i, _1_1i); assert_eq!(_neg1_1i / _0_1i, _1_1i);
@ -907,6 +1009,7 @@ mod test {
} }
} }
} }
#[test] #[test]
fn test_neg() { fn test_neg() {
assert_eq!(-_1_0i + _0_1i, _neg1_1i); assert_eq!(-_1_0i + _0_1i, _neg1_1i);
@ -917,6 +1020,34 @@ mod test {
} }
} }
mod real_arithmetic {
use super::super::Complex;
#[test]
fn test_add() {
assert_eq!(Complex::new(4.0, 2.0) + 0.5, Complex::new(4.5, 2.0));
assert_eq!(0.5 + Complex::new(4.0, 2.0), Complex::new(4.5, 2.0));
}
#[test]
fn test_sub() {
assert_eq!(Complex::new(4.0, 2.0) - 0.5, Complex::new(3.5, 2.0));
assert_eq!(0.5 - Complex::new(4.0, 2.0), Complex::new(-3.5, -2.0));
}
#[test]
fn test_mul() {
assert_eq!(Complex::new(4.0, 2.0) * 0.5, Complex::new(2.0, 1.0));
assert_eq!(0.5 * Complex::new(4.0, 2.0), Complex::new(2.0, 1.0));
}
#[test]
fn test_div() {
assert_eq!(Complex::new(4.0, 2.0) / 0.5, Complex::new(8.0, 4.0));
assert_eq!(0.5 / Complex::new(4.0, 2.0), Complex::new(0.1, -0.05));
}
}
#[test] #[test]
fn test_to_string() { fn test_to_string() {
fn test(c : Complex64, s: String) { fn test(c : Complex64, s: String) {
@ -933,8 +1064,6 @@ mod test {
#[test] #[test]
fn test_hash() { fn test_hash() {
let a = Complex::new(0i32, 0i32); let a = Complex::new(0i32, 0i32);
let b = Complex::new(1i32, 0i32); let b = Complex::new(1i32, 0i32);
let c = Complex::new(0i32, 1i32); let c = Complex::new(0i32, 1i32);