use std::ops::{Add, Mul};
use crate::Polynomial;
fn horner_poly_evaluate<I, T, O>(x: I, coefficients: &[T]) -> O
where
O: Copy,
O: num_traits::Zero + Mul<I, Output = O> + Add<T, Output = O>,
I: Copy,
T: Copy,
{
let mut out = O::zero();
for &a in coefficients.into_iter().rev() {
out = out * x + a
}
out
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct StandardFormPolynomial<T> {
pub coefficients: Vec<T>,
}
impl<T> StandardFormPolynomial<T> {
pub fn new(coefficients: Vec<T>) -> Self {
Self { coefficients }
}
pub fn degree(&self) -> usize
where
T: num_traits::Zero,
{
let mut degree = match self.coefficients.len() {
0 => 0,
t => t - 1,
};
for coeff in self.coefficients.iter().rev() {
if coeff.is_zero() && degree > 0 {
degree -= 1;
} else {
break;
}
}
return degree;
}
}
impl<I, T> Polynomial<I, T> for StandardFormPolynomial<T>
where
I: Copy,
T: Copy + num_traits::Zero,
T: Mul<I, Output = T> + Add<T, Output = T>,
{
fn evaluate(&self, x: I) -> T {
horner_poly_evaluate(x, self.coefficients.as_ref())
}
fn degree(&self) -> usize {
StandardFormPolynomial::degree(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_polynomial_degree() {
assert_eq!(StandardFormPolynomial::<i32>::new(vec![]).degree(), 0);
assert_eq!(StandardFormPolynomial::new(vec![0]).degree(), 0);
assert_eq!(StandardFormPolynomial::new(vec![1]).degree(), 0);
assert_eq!(StandardFormPolynomial::new(vec![2, 2]).degree(), 1);
assert_eq!(StandardFormPolynomial::new(vec![3, 3, 3]).degree(), 2);
assert_eq!(StandardFormPolynomial::new(vec![0, 0, 0]).degree(), 0);
}
#[test]
fn test_polynomial_evaluate() {
let poly = StandardFormPolynomial::new(vec![1, 3, 2]);
assert_eq!(poly.evaluate(0), 1);
assert_eq!(poly.evaluate(1), 6);
assert_eq!(poly.evaluate(2), 15);
assert_eq!(poly.evaluate(3), 28);
assert_eq!(poly.evaluate(4), 45);
}
}