diff options
author | Justin Worthe <justin.worthe@gmail.com> | 2016-12-05 21:22:42 +0200 |
---|---|---|
committer | Justin Worthe <justin.worthe@gmail.com> | 2016-12-05 21:22:42 +0200 |
commit | c9073bec568efa90c85e381c12dbcd20fe86a8f0 (patch) | |
tree | 914e35b477fdc607ae0844b673bf8dde9552c22c | |
parent | 308edb5b5cd5ee6d2e2962f627612e3973f5b586 (diff) |
Refactored number traits
-rw-r--r-- | src/complex.rs | 46 | ||||
-rw-r--r-- | src/num_traits.rs | 23 | ||||
-rw-r--r-- | src/sinusoid.rs | 16 |
3 files changed, 55 insertions, 30 deletions
diff --git a/src/complex.rs b/src/complex.rs index 93495fa..228ba8f 100644 --- a/src/complex.rs +++ b/src/complex.rs @@ -1,5 +1,5 @@ use std::ops::{Add, Sub, Mul, Div, Neg}; -use ::num_traits::{Trig, Pow}; +use ::num_traits::{Trig, Pow, ArithmeticOps, SignedArithmeticOps}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Complex<T> { @@ -12,39 +12,37 @@ impl<T> Complex<T> { Complex{real: real, imag: imag} } } -impl<T> Complex<T> where T: Neg<Output=T> { +impl<T> Complex<T> where T: SignedArithmeticOps { pub fn conjugate(self) -> Complex<T> { Complex::new(self.real, -self.imag) } } -impl<T> Complex<T> where T: Trig + Mul<Output=T> + Copy { - pub fn from_polar(r: T, theta: T) -> Complex<T> { - let real = r*theta.cos(); - let imag = r*theta.sin(); - Complex::new(real, imag) - } -} - -impl<T> Complex<T> where T: Pow + Add<Output=T> + Copy { +impl<T> Complex<T> where T: Pow + ArithmeticOps + Copy { pub fn magnitude(self) -> T { (self.real.pow(2) + self.imag.pow(2)).sqrt() } } -impl<T> Complex<T> where T: Trig + Copy { +impl<T> Complex<T> where T: Trig { pub fn angle(self) -> T { self.imag.atan2(self.real) } } -impl<T> Complex<T> where T: Trig + Pow + Add<Output=T> + Copy { +impl<T> Complex<T> where T: Trig + Pow + ArithmeticOps + Copy { + pub fn from_polar(r: T, theta: T) -> Complex<T> { + let real = r*theta.cos(); + let imag = r*theta.sin(); + Complex::new(real, imag) + } + pub fn to_polar(self) -> (T, T) { (self.magnitude(), self.angle()) } } -impl<T> Add for Complex<T> where T: Add<Output=T> + Copy { +impl<T> Add for Complex<T> where T: ArithmeticOps + Copy { type Output = Complex<T>; fn add(self, other: Self) -> Self { @@ -54,7 +52,7 @@ impl<T> Add for Complex<T> where T: Add<Output=T> + Copy { } } -impl<T> Sub for Complex<T> where T: Sub<Output=T> + Copy { +impl<T> Sub for Complex<T> where T: ArithmeticOps + Copy { type Output = Complex<T>; fn sub(self, other: Self) -> Self { @@ -64,7 +62,7 @@ impl<T> Sub for Complex<T> where T: Sub<Output=T> + Copy { } } -impl<T> Mul for Complex<T> where T: Add<Output=T> + Mul<Output=T> + Sub<Output=T> + Copy { +impl<T> Mul for Complex<T> where T: ArithmeticOps + Copy { type Output = Complex<T>; fn mul(self, other: Self) -> Self { @@ -74,7 +72,7 @@ impl<T> Mul for Complex<T> where T: Add<Output=T> + Mul<Output=T> + Sub<Output=T } } -impl<T> Div for Complex<T> where T: Add<Output=T> + Mul<Output=T> + Sub<Output=T> + Div<Output=T> + Neg<Output=T> + Copy { +impl<T> Div for Complex<T> where T: SignedArithmeticOps + Copy { type Output = Complex<T>; fn div(self, other: Self) -> Self { @@ -90,6 +88,14 @@ impl<T> Div for Complex<T> where T: Add<Output=T> + Mul<Output=T> + Sub<Output=T } } +impl<T> Neg for Complex<T> where T: SignedArithmeticOps + Copy { + type Output = Complex<T>; + + fn neg(self) -> Self { + Complex::new(-self.real, -self.imag) + } +} + #[cfg(test)] mod tests { use super::*; @@ -124,6 +130,12 @@ mod tests { } #[test] + fn neg() { + let a = Complex::new(6, 8); + assert_eq!(-a, Complex::new(0, 0)-a); + } + + #[test] fn from_polar() { let right = Complex::from_polar(1.0 as f32, 0.0 as f32); assert!((right.real-1.0).abs() < f32::EPSILON); diff --git a/src/num_traits.rs b/src/num_traits.rs index a754787..030e5c4 100644 --- a/src/num_traits.rs +++ b/src/num_traits.rs @@ -86,23 +86,36 @@ impl_int_pow!(u32); impl_int_pow!(u64); -pub trait Float { +use std::ops::{Add, Sub, Mul, Div, Rem, Neg}; + +pub trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + Rem<Output=Self> where Self: std::marker::Sized {} +impl<T> ArithmeticOps for T where T: Add<Output=T> + Sub<Output=T> + Mul<Output=T> + Div<Output=T> + Rem<Output=T> {} + +pub trait SignedArithmeticOps: ArithmeticOps + Neg<Output=Self> where Self: std::marker::Sized {} +impl<T> SignedArithmeticOps for T where T: ArithmeticOps + Neg<Output=T> {} + + +pub trait FractionOps { fn recip(self) -> Self; fn pi() -> Self; + fn two_pi() -> Self; } -macro_rules! impl_float { +macro_rules! impl_fraction_float { ($t: ty, $pi: expr) => { - impl Float for $t { + impl FractionOps for $t { fn recip(self) -> Self { self.recip() } fn pi() -> Self { $pi } + fn two_pi() -> Self { + 2.0 * $pi + } } } } -impl_float!(f32, std::f32::consts::PI); -impl_float!(f64, std::f64::consts::PI); +impl_fraction_float!(f32, std::f32::consts::PI); +impl_fraction_float!(f64, std::f64::consts::PI); diff --git a/src/sinusoid.rs b/src/sinusoid.rs index 1f60b03..cc9c20c 100644 --- a/src/sinusoid.rs +++ b/src/sinusoid.rs @@ -1,6 +1,5 @@ use std::cmp::{PartialOrd}; -use std::ops::{Add, Sub, Mul, Div, Rem}; -use ::num_traits::{Trig, Float}; +use ::num_traits::{Trig, ArithmeticOps, FractionOps}; // generic number type, but realistically it's only useful for // floats. Maybe also complex<float> @@ -20,21 +19,22 @@ impl<T> Sinusoid<T> { } } } -impl<T> Sinusoid<T> where T: Float + Copy { +impl<T> Sinusoid<T> where T: FractionOps + Copy { pub fn period(&self) -> T { self.frequency.recip() } } -impl<T> Sinusoid<T> where T: Float + Add<Output=T> + Sub<Output=T> + Mul<Output=T> + Div<Output=T> + From<u16> + Trig + Copy + PartialOrd + Rem<Output=T> { +impl<T> Sinusoid<T> where T: FractionOps + ArithmeticOps + Trig + Copy { pub fn radial_frequency(&self) -> T { - (T::from(2))*T::pi()*self.frequency + T::two_pi()*self.frequency } pub fn sample(&self, t: T) -> T { (self.radial_frequency()*(t%self.period()) + self.phase).cos() * self.amplitude } +} +impl<T> Sinusoid<T> where T: FractionOps + ArithmeticOps + From<u16> + Trig + Copy + PartialOrd { //inclusive of start, exclusive of end pub fn sample_range(&self, start: T, end: T, sample_rate: T) -> Vec<T> { - let sample_resolution = T::from(1) / sample_rate; let mut result = Vec::new(); let mut i: u16 = 0; loop { @@ -68,7 +68,7 @@ mod tests { #[test] fn sample() { - let sinusoid = Sinusoid::new(1.0 as f32, 1.0, -f32::consts::PI/2.0); //AKA sin + let sinusoid = Sinusoid::new(1.0 as f32, 1.0, -f32::consts::FRAC_PI_2); //AKA sin assert!((sinusoid.sample(0.0)-0.0) < f32::EPSILON); assert!((sinusoid.sample(0.25)-1.0) < f32::EPSILON); @@ -79,7 +79,7 @@ mod tests { #[test] fn sample_range() { - let sinusoid = Sinusoid::new(1.0 as f32, 1.0, -f32::consts::PI/2.0); //AKA sin + let sinusoid = Sinusoid::new(1.0 as f32, 1.0, -f32::consts::FRAC_PI_2); //AKA sin let samples = sinusoid.sample_range(0.0, 100.0, 4.0); println!("Epsilon is {}", f32::EPSILON); assert_eq!(samples.len(), 400); |