diff options
Diffstat (limited to 'src/lerp')
-rw-r--r-- | src/lerp/poly.rs | 119 | ||||
-rw-r--r-- | src/lerp/poly/iter.rs | 38 |
2 files changed, 157 insertions, 0 deletions
diff --git a/src/lerp/poly.rs b/src/lerp/poly.rs new file mode 100644 index 0000000..961c56c --- /dev/null +++ b/src/lerp/poly.rs @@ -0,0 +1,119 @@ +mod iter; + +use iter::Iter; +use std::fmt; +use std::ops::{Add, Mul, Sub}; + +#[derive(PartialEq, Debug, Clone)] +pub struct Poly { + data: Vec<f32>, + degree: usize, +} + +impl Poly { + pub fn new(data: Vec<f32>) -> Poly { + if data.len() > 0 { + let mut i = data.len() - 1; + while data[i] == 0.0 && i > 0 { + i -= 1; + } + Poly { data, degree: i } + } else { + Poly { data, degree: 0 } + } + } + + pub fn degree(&self) -> usize { + self.degree + } + + fn iter(&self) -> Iter { + Iter::new(self.data.clone(), self.degree()) + } +} + +impl Add for &Poly { + type Output = Poly; + + fn add(self, other: Self) -> Poly { + Poly::new(self.iter().zip(other.iter()).map(|(x, y)| x + y).collect()) + } +} + +impl Sub for &Poly { + type Output = Poly; + + fn sub(self, other: Self) -> Poly { + Poly::new(self.iter().zip(other.iter()).map(|(x, y)| x - y).collect()) + } +} + +impl Mul for &Poly { + type Output = Poly; + + fn mul(self, other: Self) -> Poly { + let mut r = Vec::new(); + for i in 0..other.degree() + 1 { + let mut prefix = vec![0.0; i]; + let mut suffix: Vec<f32> = self + .iter() + .take(self.degree() + 1) + .map(|x| x * other.data[i]) + .collect(); + prefix.append(&mut suffix); + r.push(Poly::new(prefix)); + } + r.iter().fold(Poly::new(vec![0.0]), |acc, x| &acc + x) + } +} + +impl fmt::Display for &Poly { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut s = String::new(); + for i in 0..self.data.len() { + s.push_str(&self.data[i].clone().to_string()); + if i < self.data.len() - 1 { + s.push_str(", "); + } + } + write!(f, "{}", s) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn mul_test() { + let a = Poly::new(vec![1.0, 2.0, 3.0]); + let b = Poly::new(vec![1.0, 2.0]); + assert_eq!(&a * &b, Poly::new(vec![1.0, 4.0, 7.0, 6.0])); + } + + #[test] + fn add_test() { + let a = Poly::new(vec![1.0]); + let b = Poly::new(vec![0.0, 0.0, 0.0, 1.0]); + assert_eq!(&a + &b, Poly::new(vec![1.0, 0.0, 0.0, 1.0])); + } + + #[test] + fn sub_test() { + let a = Poly::new(vec![1.0, 2.0, 3.0]); + let b = Poly::new(vec![1.0, 1.0, 1.0]); + assert_eq!(&a - &b, Poly::new(vec![0.0, 1.0, 2.0])); + } + + #[test] + fn degree_is_five() { + let p = Poly::new(vec![0.0, 0.0, 0.0, 0.0, 0.0, 2.0]); + assert_eq!(p.degree(), 5); + } + + #[test] + fn degree_is_zero() { + let p = Poly::new(vec![0.0; 6]); + assert_eq!(p.degree(), 0); + } +} diff --git a/src/lerp/poly/iter.rs b/src/lerp/poly/iter.rs new file mode 100644 index 0000000..90cc4b5 --- /dev/null +++ b/src/lerp/poly/iter.rs @@ -0,0 +1,38 @@ +use std::cmp; +use std::iter::{Take, Zip}; + +pub struct Iter { + index: usize, + data: Vec<f32>, + degree: usize, +} + +impl Iter { + pub fn new(data: Vec<f32>, degree: usize) -> Iter { + Iter { + index: 0, + data, + degree, + } + } + + pub fn zip(self, other: Self) -> Zip<Take<Iter>, Take<Iter>> { + let deg = cmp::max(self.degree, other.degree) + 1; + let a = self.take(deg); + let b = other.take(deg); + a.zip(b) + } +} + +impl Iterator for Iter { + type Item = f32; + + fn next(&mut self) -> Option<f32> { + self.index += 1; + if self.index <= self.data.len() { + Some(self.data[self.index - 1]) + } else { + Some(0.0) + } + } +} |