summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/complex.rs46
-rw-r--r--src/num_traits.rs23
-rw-r--r--src/sinusoid.rs16
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);