#![allow(dead_code)]
pub fn poly_eval(coeffs: &[f64], x: f64) -> f64 {
if coeffs.is_empty() {
return 0.0;
}
let mut result = 0.0f64;
for &c in coeffs.iter().rev() {
result = result * x + c;
}
result
}
pub fn poly_deriv(coeffs: &[f64], x: f64) -> f64 {
if coeffs.len() < 2 {
return 0.0;
}
let deriv: Vec<f64> = coeffs[1..]
.iter()
.enumerate()
.map(|(i, &c)| c * (i + 1) as f64)
.collect();
poly_eval(&deriv, x)
}
pub struct Polynomial {
pub coeffs: Vec<f64>,
}
pub fn new_polynomial(coeffs: Vec<f64>) -> Polynomial {
Polynomial { coeffs }
}
impl Polynomial {
pub fn eval(&self, x: f64) -> f64 {
poly_eval(&self.coeffs, x)
}
pub fn deriv_at(&self, x: f64) -> f64 {
poly_deriv(&self.coeffs, x)
}
pub fn degree(&self) -> usize {
if self.coeffs.is_empty() {
0
} else {
self.coeffs.len() - 1
}
}
pub fn newton_root(&self, x0: f64, max_iter: usize, tol: f64) -> Option<f64> {
let mut x = x0;
for _ in 0..max_iter {
let fx = self.eval(x);
if fx.abs() < tol {
return Some(x);
}
let dfx = self.deriv_at(x);
if dfx.abs() < 1e-15 {
return None;
}
x -= fx / dfx;
}
if self.eval(x).abs() < tol {
Some(x)
} else {
None
}
}
pub fn mul(&self, other: &Polynomial) -> Polynomial {
let n = self.coeffs.len();
let m = other.coeffs.len();
if n == 0 || m == 0 {
return Polynomial { coeffs: vec![] };
}
let mut result = vec![0.0f64; n + m - 1];
for (i, &a) in self.coeffs.iter().enumerate() {
for (j, &b) in other.coeffs.iter().enumerate() {
result[i + j] += a * b;
}
}
Polynomial { coeffs: result }
}
}
pub fn horner_eval(coeffs: &[f64], x: f64) -> f64 {
poly_eval(coeffs, x)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_poly_eval_constant() {
assert!((poly_eval(&[5.0], 999.0) - 5.0).abs() < 1e-12);
}
#[test]
fn test_poly_eval_linear() {
assert!((poly_eval(&[1.0, 2.0], 3.0) - 7.0).abs() < 1e-12);
}
#[test]
fn test_poly_eval_quadratic() {
assert!((poly_eval(&[0.0, 0.0, 1.0], 4.0) - 16.0).abs() < 1e-12);
}
#[test]
fn test_poly_deriv() {
assert!((poly_deriv(&[0.0, 0.0, 1.0], 3.0) - 6.0).abs() < 1e-12);
}
#[test]
fn test_newton_root_sqrt2() {
let p = new_polynomial(vec![-2.0, 0.0, 1.0]);
let root = p.newton_root(1.5, 50, 1e-10).expect("should succeed");
assert!((root - 2.0f64.sqrt()).abs() < 1e-8);
}
#[test]
fn test_degree() {
let p = new_polynomial(vec![1.0, 2.0, 3.0]);
assert_eq!(p.degree(), 2);
}
#[test]
fn test_poly_mul() {
let p1 = new_polynomial(vec![1.0, 1.0]);
let p2 = new_polynomial(vec![1.0, -1.0]);
let prod = p1.mul(&p2);
assert!((prod.coeffs[0] - 1.0).abs() < 1e-12);
assert!(prod.coeffs[1].abs() < 1e-12);
assert!((prod.coeffs[2] - (-1.0)).abs() < 1e-12);
}
#[test]
fn test_horner_eval() {
let coeffs = vec![1.0, -3.0, 2.0];
let x = 5.0;
assert!((horner_eval(&coeffs, x) - poly_eval(&coeffs, x)).abs() < 1e-12);
}
#[test]
fn test_empty_poly_eval() {
assert_eq!(poly_eval(&[], 10.0), 0.0);
}
}