From c9073bec568efa90c85e381c12dbcd20fe86a8f0 Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Mon, 5 Dec 2016 21:22:42 +0200 Subject: Refactored number traits --- src/complex.rs | 46 +++++++++++++++++++++++++++++----------------- src/num_traits.rs | 23 ++++++++++++++++++----- 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 { @@ -12,39 +12,37 @@ impl Complex { Complex{real: real, imag: imag} } } -impl Complex where T: Neg { +impl Complex where T: SignedArithmeticOps { pub fn conjugate(self) -> Complex { Complex::new(self.real, -self.imag) } } -impl Complex where T: Trig + Mul + Copy { - pub fn from_polar(r: T, theta: T) -> Complex { - let real = r*theta.cos(); - let imag = r*theta.sin(); - Complex::new(real, imag) - } -} - -impl Complex where T: Pow + Add + Copy { +impl Complex where T: Pow + ArithmeticOps + Copy { pub fn magnitude(self) -> T { (self.real.pow(2) + self.imag.pow(2)).sqrt() } } -impl Complex where T: Trig + Copy { +impl Complex where T: Trig { pub fn angle(self) -> T { self.imag.atan2(self.real) } } -impl Complex where T: Trig + Pow + Add + Copy { +impl Complex where T: Trig + Pow + ArithmeticOps + Copy { + pub fn from_polar(r: T, theta: T) -> Complex { + 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 Add for Complex where T: Add + Copy { +impl Add for Complex where T: ArithmeticOps + Copy { type Output = Complex; fn add(self, other: Self) -> Self { @@ -54,7 +52,7 @@ impl Add for Complex where T: Add + Copy { } } -impl Sub for Complex where T: Sub + Copy { +impl Sub for Complex where T: ArithmeticOps + Copy { type Output = Complex; fn sub(self, other: Self) -> Self { @@ -64,7 +62,7 @@ impl Sub for Complex where T: Sub + Copy { } } -impl Mul for Complex where T: Add + Mul + Sub + Copy { +impl Mul for Complex where T: ArithmeticOps + Copy { type Output = Complex; fn mul(self, other: Self) -> Self { @@ -74,7 +72,7 @@ impl Mul for Complex where T: Add + Mul + Sub Div for Complex where T: Add + Mul + Sub + Div + Neg + Copy { +impl Div for Complex where T: SignedArithmeticOps + Copy { type Output = Complex; fn div(self, other: Self) -> Self { @@ -90,6 +88,14 @@ impl Div for Complex where T: Add + Mul + Sub Neg for Complex where T: SignedArithmeticOps + Copy { + type Output = Complex; + + fn neg(self) -> Self { + Complex::new(-self.real, -self.imag) + } +} + #[cfg(test)] mod tests { use super::*; @@ -123,6 +129,12 @@ mod tests { assert_eq!(a/b, Complex::new(2, 0)); } + #[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); 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 + Sub + Mul + Div + Rem where Self: std::marker::Sized {} +impl ArithmeticOps for T where T: Add + Sub + Mul + Div + Rem {} + +pub trait SignedArithmeticOps: ArithmeticOps + Neg where Self: std::marker::Sized {} +impl SignedArithmeticOps for T where T: ArithmeticOps + Neg {} + + +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 @@ -20,21 +19,22 @@ impl Sinusoid { } } } -impl Sinusoid where T: Float + Copy { +impl Sinusoid where T: FractionOps + Copy { pub fn period(&self) -> T { self.frequency.recip() } } -impl Sinusoid where T: Float + Add + Sub + Mul + Div + From + Trig + Copy + PartialOrd + Rem { +impl Sinusoid 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 Sinusoid where T: FractionOps + ArithmeticOps + From + Trig + Copy + PartialOrd { //inclusive of start, exclusive of end pub fn sample_range(&self, start: T, end: T, sample_rate: T) -> Vec { - 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); -- cgit v1.2.3