1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
use num_traits::ops::mul_add::MulAddAssign; use num_traits::Zero; /// Evaluate a polynomial of arbitrary rank using Horner's method. /// /// Horner's method goes like this: to find 𝑎𝑥³+𝑏𝑥²+𝑐𝑥+𝑑, you evaluate 𝑥(𝑥(𝑎𝑥+𝑏)+𝑐)+𝑑. /// /// That's what this function does too. /// /// You provide a value for `𝑥` and a slice of values for the coefficients `&[𝑎, 𝑏, 𝑐, 𝑑, …]`. /// The cardinality of the slice of coefficients must equal the degree of the polynomial plus one, /// except for the special case of the whole expression being just 0 in which case a slice of /// length zero means the same (gives you the same result) as if the slice was equal to `&[0]` /// or any other number of all zeros. /// /// Here are some examples demonstrating use of eval_polynomial: /// /// ``` /// use horner::eval_any_rank_polynomial; /// /// // Evaluating the polynomial 72𝑥²+81𝑥+99 with 𝑥 = 5 /// let val = eval_any_rank_polynomial(5, &[72, 81, 99]); /// /// // Traditional calculation. /// let trad = 72 * 5_i32.pow(2) + 81 * 5 + 99; /// /// assert_eq!(val, trad); /// ``` /// /// ``` /// # use horner::eval_any_rank_polynomial; /// // Here we have the "polynomial" 42, which is to say, 42𝑥⁰. Evaluated with 𝑥 = 9000 /// assert_eq!(42, eval_any_rank_polynomial(9000, &[42])); /// ``` /// /// ``` /// # use horner::eval_any_rank_polynomial; /// // 23𝑥⁹+0𝑥⁸+27𝑥⁷+0𝑥⁶-5𝑥⁵+0𝑥⁴+0𝑥³+0𝑥²+0𝑥ⁱ+0𝑥⁰ /// // Written simply: 23𝑥⁹+27𝑥⁷-5𝑥⁵ /// // Evaluated with 𝑥 = 99 /// /// let val = eval_any_rank_polynomial(99_i128, &[23, 0, 27, 0, -5, 0, 0, 0, 0, 0]); /// let trad = 23 * 99_i128.pow(9) + 27 * 99_i128.pow(7) - 5 * 99_i128.pow(5); /// /// assert_eq!(val, trad); /// ``` /// /// ``` /// # use horner::eval_any_rank_polynomial; /// // The "polynomial" 0. Represented in it's simplest form, the list of coefficents is empty. /// // Evaluated with 𝑥 = 222 /// assert_eq!(0, eval_any_rank_polynomial(222, &[])); /// ``` /// /// See also: [eval_known_rank_polynomial] pub fn eval_any_rank_polynomial<T: Zero + MulAddAssign + Copy> (x: T, coefficients: &[T]) -> T { if let Some((&k, coefficients)) = coefficients.split_first() { let mut val = k; for &k in coefficients { val.mul_add_assign(x, k); } val } else { T::zero() } } /// Evaluate a polynomial of rank known at compile-time using Horner's method. /// /// For now this function simply calls [eval_any_rank_polynomial], but the idea /// is that in the future we may be able to optimize our code further in the case /// where the rank of the polynomial is known at compile-time. /// /// Example usage: /// /// ``` /// use horner::eval_known_rank_polynomial; /// /// assert_eq!(0, eval_known_rank_polynomial(-4, &[1, 4])); /// ``` /// /// See also: [eval_any_rank_polynomial] pub fn eval_known_rank_polynomial<T: Zero + MulAddAssign + Copy, const N: usize> (x: T, coefficients: &[T; N]) -> T { eval_any_rank_polynomial(x, coefficients) }