1+ /* *
2+ * @file
3+ * @brief Implementation of Neville's Algorithm for polynomial interpolation.
4+ * @details Neville's algorithm is an iterative method to find the value of a
5+ * polynomial that passes through a given set of n+1 points. It evaluates the
6+ * polynomial at a specific point `x` without needing to compute the
7+ * polynomial's coefficients. For more details, see:
8+ * https://en.wikipedia.org/wiki/Neville%27s_algorithm
9+ * @author [Mitrajit Ghorui](https://github.com/KeyKyrios)
10+ */
11+
12+ #include < cassert> // / for assert
13+ #include < iostream> // / for IO operations
14+ #include < stdexcept> // / for std::invalid_argument
15+ #include < vector> // / for std::vector
16+ #include < cmath> // / for fabs
17+
18+ /* *
19+ * @namespace maths
20+ * @brief Mathematical algorithms
21+ */
22+ namespace maths {
23+ /* *
24+ * @namespace nevilles_algorithm
25+ * @brief Functions for Neville's Algorithm
26+ */
27+ namespace nevilles_algorithm {
28+ /* *
29+ * @brief Evaluates the interpolating polynomial at a specific point.
30+ * @param x_coords Vector of x-coordinates of the given points.
31+ * @param y_coords Vector of y-coordinates of the given points.
32+ * @param target The x-coordinate at which to evaluate the polynomial.
33+ * @returns The interpolated y-value at the target x-coordinate.
34+ * @throws std::invalid_argument if input vectors are empty or have mismatched
35+ * sizes.
36+ */
37+ double interpolate (const std::vector<double >& x_coords,
38+ const std::vector<double >& y_coords, double target) {
39+ if (x_coords.empty () || y_coords.empty ()) {
40+ throw std::invalid_argument (" Input vectors cannot be empty." );
41+ }
42+ if (x_coords.size () != y_coords.size ()) {
43+ throw std::invalid_argument (
44+ " x and y coordinate vectors must be the same size." );
45+ }
46+
47+ int n = x_coords.size ();
48+ std::vector<double > p = y_coords; // Initialize p with y values
49+
50+ for (int k = 1 ; k < n; ++k) {
51+ for (int i = 0 ; i < n - k; ++i) {
52+ p[i] = ((target - x_coords[i + k]) * p[i] +
53+ (x_coords[i] - target) * p[i + 1 ]) /
54+ (x_coords[i] - x_coords[i + k]);
55+ }
56+ }
57+
58+ return p[0 ];
59+ }
60+ } // namespace nevilles_algorithm
61+ } // namespace maths
62+
63+ /* *
64+ * @brief Self-test implementations
65+ * @returns void
66+ */
67+ static void test () {
68+ // Test 1: Linear interpolation y = 2x + 1
69+ // Points (0, 1), (2, 5). Target x=1, expected y=3.
70+ std::vector<double > x1 = {0 , 2 };
71+ std::vector<double > y1 = {1 , 5 };
72+ double target1 = 1 ;
73+ double expected1 = 3.0 ;
74+ assert (fabs (maths::nevilles_algorithm::interpolate (x1, y1, target1) - expected1) < 1e-9 );
75+ std::cout << " Linear test passed." << std::endl;
76+
77+ // Test 2: Quadratic interpolation y = x^2
78+ // Points (0, 0), (1, 1), (3, 9). Target x=2, expected y=4.
79+ std::vector<double > x2 = {0 , 1 , 3 };
80+ std::vector<double > y2 = {0 , 1 , 9 };
81+ double target2 = 2 ;
82+ double expected2 = 4.0 ;
83+ assert (fabs (maths::nevilles_algorithm::interpolate (x2, y2, target2) - expected2) < 1e-9 );
84+ std::cout << " Quadratic test passed." << std::endl;
85+
86+ // Test 3: Negative numbers y = x^2 - 2x + 1
87+ // Points (-1, 4), (0, 1), (2, 1). Target x=1, expected y=0.
88+ std::vector<double > x3 = {-1 , 0 , 2 };
89+ std::vector<double > y3 = {4 , 1 , 1 };
90+ double target3 = 1 ;
91+ double expected3 = 0.0 ;
92+ assert (fabs (maths::nevilles_algorithm::interpolate (x3, y3, target3) - expected3) < 1e-9 );
93+ std::cout << " Negative numbers test passed." << std::endl;
94+
95+ std::cout << " All tests have successfully passed!" << std::endl;
96+ }
97+
98+ /* *
99+ * @brief Main function
100+ * @returns 0 on exit
101+ */
102+ int main () {
103+ test (); // run self-test implementations
104+ return 0 ;
105+ }
0 commit comments