#![forbid(unsafe_code)]
#[derive(Clone, Debug, PartialEq)]
pub struct Monomial {
pub c: f64, pub e: f64, }
impl Monomial {
pub fn new(c: f64, e: f64) -> Monomial {
Monomial { c, e }
}
pub fn value(&self, x: f64) -> f64 {
self.c * (x.powf(self.e))
}
pub fn add_monomial_of_same_power(&self, other: Monomial) -> Monomial {
if self.e != other.e {
panic!("Cannot add monomials with different powers of x.");
};
Monomial {
c: self.c + other.c,
e: self.e,
}
}
pub fn multiply_monomial(&self, other: Monomial) -> Monomial {
Monomial {
c: self.c * other.c,
e: self.e + other.e,
}
}
pub fn derivative(&self) -> Monomial {
Monomial {
c: self.c * self.e,
e: self.e - 1_f64,
}
}
pub fn nth_derivative(&self, n: u32) -> Monomial {
let mut new_monomial = self.clone();
for _ in 0..n {
new_monomial = new_monomial.derivative();
}
new_monomial
}
}
impl Default for Monomial {
fn default() -> Self {
Self::new(0_f64, 0_f64)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Polynomial(pub Vec<Monomial>);
impl Polynomial {
pub fn new() -> Polynomial {
Polynomial(vec![])
}
pub fn value(&self, x: f64) -> f64 {
let elements = &self.0;
let mut value = 0_f64;
for element in elements {
value += element.value(x);
}
value
}
pub fn simplified(&self) -> Polynomial {
self.simplify_by_combining_alike_powers()
.eliminate_zero_coefficients()
.sort_by_exponent()
}
pub fn simplify_by_combining_alike_powers(&self) -> Polynomial {
let elements = &self.0;
let mut simplified_elements = Polynomial::new();
let mut first_element_transferred = false;
for element in elements {
if !first_element_transferred {
simplified_elements.0.push(element.clone());
first_element_transferred = true;
continue;
}
let mut found_match = false;
for simplified_element in &mut simplified_elements.0 {
if simplified_element.e == element.e {
*simplified_element =
simplified_element.add_monomial_of_same_power(element.clone());
found_match = true;
break;
}
}
if !found_match {
simplified_elements.0.push(element.clone());
}
}
simplified_elements
}
pub fn eliminate_zero_coefficients(&self) -> Polynomial {
let elements = &self.0;
let mut new_elements = vec![];
for element in elements {
if element.c != 0_f64 {
new_elements.push(element.clone());
}
}
Polynomial(new_elements)
}
pub fn sort_by_exponent(&self) -> Polynomial {
let mut elements = self.0.clone();
elements.sort_by(|a, b| b.e.partial_cmp(&a.e).unwrap());
Polynomial(elements)
}
pub fn add_polynomial(&self, other: Polynomial) -> Polynomial {
let mut elements = self.0.clone();
elements.extend(other.0.clone());
let new_polynomial = Polynomial(elements);
new_polynomial.simplified()
}
pub fn multiply_polynomial(&self, other: Polynomial) -> Polynomial {
let mut elements = vec![];
for element1 in &self.0 {
for element2 in &other.0 {
elements.push(element1.multiply_monomial(element2.clone()));
}
}
let new_polynomial = Polynomial(elements);
new_polynomial.simplified()
}
pub fn derivative(&self) -> Polynomial {
let mut elements = vec![];
for element in &self.0 {
elements.push(element.derivative());
}
Polynomial(elements).simplified()
}
pub fn nth_derivative(&self, n: u32) -> Polynomial {
let mut new_polynomial = self.clone();
for _ in 0..n {
new_polynomial = new_polynomial.derivative();
}
new_polynomial
}
pub fn is_equal_within_tolerance_to(&self, other: Polynomial) -> bool {
let tolerance = 1e-10;
let simplified_self = self.simplified();
let simplified_other = other.simplified();
if simplified_self.0.len() != simplified_other.0.len() {
return false;
}
for (element1, element2) in simplified_self.0.iter().zip(simplified_other.0.iter()) {
if (element1.c - element2.c).abs() > tolerance
|| (element1.e - element2.e).abs() > tolerance
{
return false;
}
}
true
}
}
impl Default for Polynomial {
fn default() -> Self {
Self::new()
}
}
pub mod tests;