Why Interpolation Matters
A calibration table records a sensor's output at several known inputs. A new input falls between two recorded positions. Interpolation constructs a function that passes through the recorded pairs so that the missing value can be estimated consistently. Animation curves, tabulated physical models, and resampling all use this pattern.
This lesson covers Lagrange interpolation, Newton divided differences, and cubic splines. Lagrange and Newton are two representations of the same global polynomial for a given set of distinct nodes. A cubic spline chooses a piecewise polynomial under additional smoothness and boundary conditions, so it can give different values between the same knots. The implementations use a natural cubic spline, whose endpoint second derivatives are zero.
You will construct each representation, trace its coefficients and evaluations, implement all three in Python, C++, and Java, and check knot residuals, polynomial agreement, and the spline equations. Interpolation fits the supplied values exactly in the mathematical model; it does not establish that those values are noise-free or that the curve predicts an unknown function accurately between them.
Interpolation builds a function satisfying $g(x_i)=y_i$ at every supplied knot. The knot constraints alone do not choose a unique arbitrary function: a polynomial degree restriction or spline smoothness and boundary conditions complete the model.
Core Concepts and Terminology
Let there be $n\ge2$ data pairs $(x_i,y_i)$ with distinct real nodes. A unique polynomial $P$ of degree at most $n-1$ satisfies all $n$ interpolation conditions. Lagrange's basis expresses those conditions directly, while Newton's basis organizes the same polynomial by divided differences.
A cubic spline instead uses a polynomial of degree at most three on each interval $[x_i,x_{i+1}]$. It interpolates both endpoints and has continuous first and second derivatives across interior knots. Natural endpoint conditions are $S''(x_0)=S''(x_{n-1})=0$. Other boundary conditions generally produce another spline.
Use the small data set $(0,0),(1,1),(2,0),(3,1)$. Its global polynomial and natural spline both pass through all four knots, but at $q=1/2$ their values are $P(q)=1$ and $S(q)=3/4$. Neither value follows from the knots alone without choosing the interpolation model.
| Term | Example or definition | Role |
|---|---|---|
| Node or knot | $x_i=1$ with value $y_i=1$ | A supplied interpolation constraint. |
| Query | $q=1/2$ | Position where an interpolated value is wanted. |
| Global interpolating polynomial | Degree at most $n-1$ through $n$ distinct nodes | Common mathematical object represented by Lagrange and Newton. |
| Lagrange cardinal basis | $L_i(x_j)=1$ if $i=j$, otherwise $0$ | Makes each knot condition explicit. |
| Barycentric weight | $w_i=1/\prod_{j\ne i}(x_i-x_j)$ | Enables repeated evaluation of the Lagrange polynomial. |
| Divided difference | $f[x_i,x_{i+1}]=(y_{i+1}-y_i)/(x_{i+1}-x_i)$ | Builds Newton coefficients on nonuniform nodes. |
| Cubic spline piece | $a_i+b_it+c_it^2+d_it^3$, $t=q-x_i$ | Uses local coordinates on one interval. |
| Natural boundary condition | Endpoint second derivatives equal zero | Completes the spline model; does not mean zero endpoint slopes. |
| Knot residual | $\max_i\lvert g(x_i)-y_i\rvert$ | Checks interpolation constraints, not unknown between-knot error. |
| Extrapolation | A query outside the knot interval | Has different risks and an explicit API policy. |
All three supplied implementations require the same data format: at least two finite $[x,y]$ rows with strictly increasing nodes and a finite representable total span. This shared ordering is useful for interval lookup in the spline. Polynomial formulas themselves do not require increasing order mathematically; changing the order changes Newton's coefficients but not the exact interpolating polynomial.
How Interpolation Works, Step by Step
1. Validate and copy the data. Reject mismatched row shapes, nonfinite values, duplicate nodes, and unsorted nodes. Do not merge close nodes using an arbitrary tolerance: distinct coordinates may represent distinct measurements, and near-coincident nodes need a conditioning decision rather than silent replacement. The code also rejects unsupported arithmetic overflow or weight underflow.
2. Construct the Lagrange polynomial. Define
$$ L_i(q)=\prod_{j\ne i}\frac{q-x_j}{x_i-x_j},\qquad P(q)=\sum_{i=0}^{n-1}y_iL_i(q). $$
At a knot, all but one cardinal basis value vanish. Directly evaluating all products costs $O(n^2)$ per query. The programs instead precompute barycentric weights and use the equivalent second barycentric form
$$ P(q)=\frac{\sum_i w_i y_i/(q-x_i)}{\sum_i w_i/(q-x_i)},\qquad q\ne x_i. $$
If the query exactly equals a knot, return its recorded value before forming a denominator. A merely nearby query still uses the formula. A common nonzero scaling of all weights cancels from the ratio; the code normalizes them by their largest magnitude. During evaluation it also multiplies every term by $\min_i\lvert q-x_i\rvert$, avoiding a large reciprocal when the query is close to a knot. These changes improve arithmetic behavior without changing the exact polynomial.
3. Construct Newton divided differences. Start with $d_i^{(0)}=y_i$ and define
$$ d_i^{(k)}=\frac{d_i^{(k-1)}-d_{i-1}^{(k-1)}}{x_i-x_{i-k}},\qquad i\ge k. $$
The Newton coefficients are $c_k=d_k^{(k)}=f[x_0,\ldots,x_k]$, giving
$$ P(q)=c_0+c_1(q-x_0)+c_2(q-x_0)(q-x_1)+\cdots +c_{n-1}\prod_{j=0}^{n-2}(q-x_j). $$
The code stores only one coefficient array. At order $k$, update indices from $n-1$ down to $k$ so both numerator entries still belong to the previous order. Updating left to right would overwrite a value before it is used.
Evaluate Newton's form with a nested recurrence: start $v=c_{n-1}$, then for $i=n-2,\ldots,0$ replace $v$ by $c_i+(q-x_i)v$. This uses $O(n)$ arithmetic and avoids separately expanding monomials or multiplying every basis product.
4. Construct a natural cubic spline through its second derivatives. Let $h_i=x_{i+1}-x_i\gt0$, $s_i=(y_{i+1}-y_i)/h_i$, and $M_i=S''(x_i)$. Set $M_0=M_{n-1}=0$. Continuity of the first derivative at each interior knot yields
$$ h_{i-1}M_{i-1}+2(h_{i-1}+h_i)M_i+h_iM_{i+1} =6(s_i-s_{i-1}),\qquad 1\le i\le n-2. $$
This is a tridiagonal system for the interior second derivatives. The teaching code explicitly builds it in nested arrays and solves it using dense Gaussian elimination with partial row pivoting. It scales the matrix and right-hand side by the matrix's maximum entry magnitude, selects the largest available pivot magnitude in each column, swaps the entire matrix row and matching right-hand-side value, eliminates below, and back-substitutes.
The dimensionless pivot tolerance, default $10^{-12}$, rejects a normalized pivot at or below the threshold. It is a numerical acceptance policy, not proof that valid knots are mathematically singular. The natural-spline interior matrix is symmetric positive definite and strictly diagonally dominant for positive interval widths; a specialized tridiagonal solver can exploit that structure in linear time. The dense version is included to make the solve and pivoting explicit, with its higher cost stated below.
For each interval, convert the second derivatives to local cubic coefficients:
$$ \begin{aligned} a_i&=y_i,\\ b_i&=s_i-\frac{h_i(2M_i+M_{i+1})}{6},\\ c_i&=M_i/2,\\ d_i&=\frac{M_{i+1}-M_i}{6h_i}. \end{aligned} $$
The spline's $c_i$ here denotes a local quadratic coefficient, while Newton's $c_i$ above denotes a divided difference; they are stored separately in the code. With just two knots, there are no interior unknowns and the natural spline is the straight line between them.
5. Evaluate with an explicit domain policy. Lagrange and Newton accept finite queries inside or outside the knot range, subject to arithmetic checks. The natural-spline method rejects queries outside $[x_0,x_{n-1}]$. For an accepted spline query, binary search chooses its interval, then evaluate $((d_it+c_i)t+b_i)t+a_i$. At the final knot the search selects the final interval.
flowchart TD
A["Validate and copy ordered knot rows"] --> B["Build normalized barycentric weights"]
B --> C["Build Newton coefficients with descending updates"]
C --> D{"Interior spline unknowns?"}
D -->|Yes| E["Assemble system; pivot, eliminate, back-substitute"]
D -->|No| F["Use zero endpoint second derivatives"]
E --> G["Build local cubic coefficients"]
F --> G
G --> H{"Requested representation?"}
H -->|Lagrange| I{"Query exactly a knot?"}
I -->|Yes| J["Return recorded value"]
I -->|No| K["Evaluate scaled barycentric ratio"]
H -->|Newton| L["Evaluate nested polynomial"]
H -->|Spline| M{"Query in knot range?"}
M -->|No| N["Raise query-domain error"]
M -->|Yes| O["Binary search interval; evaluate local cubic"]
The diagram assumes successful finite arithmetic and an accepted pivot sequence. An invalid input, zero computed barycentric denominator, unaccepted pivot, or nonfinite checked result raises an exception. Building the combined model prepares all three representations; an application needing only one can separate the preprocessing.
Worked Example with a Full Trace
Use $(x_i,y_i)=(0,0),(1,1),(2,0),(3,1)$ and query $q=1/2$. First compute every Lagrange basis contribution:
| Index $i$ | $L_i(1/2)$ | $y_i$ | Contribution $y_iL_i(1/2)$ |
|---|---|---|---|
| $0$ | $5/16$ | $0$ | $0$ |
| $1$ | $15/16$ | $1$ | $15/16$ |
| $2$ | $-5/16$ | $0$ | $0$ |
| $3$ | $1/16$ | $1$ | $1/16$ |
The basis values sum to $1$, and the contributions sum to $P(1/2)=1$. Raw barycentric weights are $[-1/6,1/2,-1/2,1/6]$; the normalized weights used in code are $[-1/3,1,-1,1/3]$. After scaling each term by the nearest-node distance $1/2$, the four denominator terms are $[-1/3,-1,1/3,-1/15]$. Both the numerator and denominator total $-16/15$, giving the same value $1$.
The complete divided-difference triangle is:
| Node | Value | Order $1$ | Order $2$ | Order $3$ |
|---|---|---|---|---|
| $0$ | $0$ | — | — | — |
| $1$ | $1$ | $1$ | — | — |
| $2$ | $0$ | $-1$ | $-1$ | — |
| $3$ | $1$ | $1$ | $1$ | $2/3$ |
Thus $c=[0,1,-1,2/3]$ and $P(q)=q-q(q-1)+(2/3)q(q-1)(q-2)$. Nested evaluation at $1/2$ visits every coefficient:
- Start $v=2/3$.
- At index $2$, $v=-1+(1/2-2)(2/3)=-2$.
- At index $1$, $v=1+(1/2-1)(-2)=2$.
- At index $0$, $v=0+(1/2-0)(2)=1$.
For the natural spline, all interval widths are $1$ and the secant slopes are $[1,-1,1]$. With $M_0=M_3=0$, the complete interior system is
$$ \begin{bmatrix}4&1\\1&4\end{bmatrix} \begin{bmatrix}M_1\\M_2\end{bmatrix} =\begin{bmatrix}-12\\12\end{bmatrix}. $$
The first pivot is $4$; the maximum-magnitude row is already first. Eliminate the lower entry with multiplier $1/4$, obtaining the second row $[0,15/4]$ with right-hand side $15$. Back-substitution gives $M_2=4$, then $M_1=(-12-4)/4=-4$. The code first divides the whole system by $4$, so its pivot values are $1$ and $15/16$ with the same multiplier and final solution.
All three local spline pieces are now determined:
| Interval | Local coordinate | $a_i$ | $b_i$ | $c_i$ | $d_i$ |
|---|---|---|---|---|---|
| $[0,1]$ | $t=q$ | $0$ | $5/3$ | $0$ | $-2/3$ |
| $[1,2]$ | $t=q-1$ | $1$ | $-1/3$ | $-2$ | $4/3$ |
| $[2,3]$ | $t=q-2$ | $0$ | $-1/3$ | $2$ | $-2/3$ |
The query belongs to the first interval, so $S(1/2)=(5/3)(1/2)-(2/3)(1/2)^3=3/4$. At the interior knot $1$, the adjoining first derivatives both equal $-1/3$ and the second derivatives both equal $-4$; at knot $2$, they are $-1/3$ and $4$. The endpoint second derivatives are zero, completing the natural boundary conditions.
Trace It by Hand
The first two interior spline equations are $4M_1+M_2=-12$ and $M_1+4M_2=12$. Predict the elimination multiplier, the reduced second equation, and the first interval's interpolated value at $q=1/2$.
Reveal: subtract $1/4$ of the first row from the second to get $(15/4)M_2=15$. Then $M_2=4$, $M_1=-4$, and the first cubic is $(5/3)t-(2/3)t^3$, giving $3/4$ at $t=1/2$.
Compare that with the Newton result $1$. The disagreement is expected: the unique degree-at-most-three polynomial and the natural spline satisfy different between-knot constraints.
Implementation in Python, C++, and Java
Each complete program constructs a combined Models object from nested $[x,y]$ rows. It exposes lagrange(q), newton(q), and spline(q), along with normalized barycentric weights, Newton coefficients, spline second derivatives, and local cubic coefficients. Inputs are copied, and construction does not reorder or modify the caller's data.
The generic spline-system solver uses partial row pivoting and a normalized pivot tolerance of $10^{-12}$. The class uses direct $O(n^2)$ weight construction and checks for lost or nonfinite weights; it is intended for moderate knot counts and numerical scales. Common weight normalization and query-distance scaling do not cure every extreme spacing or conditioning problem.
The driver uses exactly the four knots and query from the full trace. It checks known between-knot values, the maximum knot residual across all representations, agreement of the two polynomial forms, and the interior spline-system residual. The local coefficient rows have order $[a_i,b_i,c_i,d_i]$ in powers of $q-x_i$.
All three print:
lagrange P(0.5) = 1.000000newton P(0.5) = 1.000000natural spline S(0.5) = 0.750000max knot residual = 0.000000polynomial agreement error = 0.000000spline system residual = 0.000000check = PASS
A knot residual can be zero by construction; barycentric evaluation deliberately returns the supplied value at an exact knot. That check alone cannot validate all coefficients or establish between-knot accuracy. The known query values and spline system give additional checks; derivative-continuity and independent-reference tests are useful when changing the implementation.
Complexity, Correctness, and Invariants
Let $n$ be the number of knots. Separate preprocessing from query cost: an interpolant may be built once and evaluated thousands of times. The space column distinguishes stored model data from temporary construction workspace.
| Representation | Preprocessing | One query | Storage and construction workspace | Main assumptions |
|---|---|---|---|---|
| Direct Lagrange product formula | None beyond input validation | $\Theta(n^2)$ | $O(1)$ extra evaluation workspace beyond the knots | Distinct nodes; repeated products can be numerically troublesome |
| Implemented barycentric Lagrange | $\Theta(n^2)$ for weights | $O(n)$; exact first-knot query can return in $O(1)$ | $O(n)$ stored weights and query workspace | Nonzero representable weights and usable denominator |
| Implemented Newton divided differences | $\Theta(n^2)$ | $\Theta(n)$ nested evaluation | $O(n)$ stored coefficients; in-place construction workspace | Distinct nodes; ordering affects numerical behavior |
| Implemented natural spline with dense pivoted solve | $O(n^3)$, with $O(n^2)$ peak workspace | $O(\log n)$ search plus constant cubic evaluation | $O(n)$ stored model after construction | Ordered knots, natural endpoint conditions, accepted pivots |
| Natural spline with a specialized tridiagonal solver | $\Theta(n)$ | $O(\log n)$ search plus constant cubic evaluation | $O(n)$ storage and workspace | Same spline model; uses its tridiagonal structure; not the supplied solver |
The combined class builds all three models, so its dense solve dominates preprocessing and peak space for large $n$. With two knots no system is solved. For ordinary valid inputs of a fixed size, the construction loop bounds are data-independent; pivot choices affect arithmetic and row swaps but not the stated asymptotic order. Newton query work is fixed, while barycentric exact-knot exits and binary-search paths vary. A distribution-free average query cost is not defined without a query model. If a spline's interval index is already known, its evaluation itself is $O(1)$.
Polynomial existence and uniqueness. Lagrange's cardinal identities give a polynomial meeting every knot condition. If two polynomials of degree at most $n-1$ met those conditions, their difference would have $n$ distinct roots while having degree at most $n-1$, so it must be zero. Therefore the Lagrange and Newton forms represent the same exact polynomial.
Newton's construction invariant. At divided-difference order $k$, the entries about to be used belong to order $k-1$. Descending index updates preserve those inputs until they have been consumed; the diagonal entry at index $k$ becomes the coefficient for $\prod_{j=0}^{k-1}(q-x_j)$. Nested evaluation maintains the remaining suffix of that polynomial without expanding its powers.
Spline existence and uniqueness. Each local cubic is determined by its endpoint values and second derivatives. The interior equations impose continuity of the first derivative; shared $M_i$ impose continuity of the second derivative. With natural endpoint values fixed, the interior matrix has positive diagonal, positive interval widths, and strict diagonal dominance. Symmetry and positivity give a unique solution. Partial pivoting is an equivalent row-operation solve; the normalized tolerance can still reject a numerically difficult representation even when the mathematical system is nonsingular.
Lagrange's cardinal basis and Newton's divided differences enforce the same unique polynomial interpolation constraints. A natural spline instead preserves knot values and joins local cubics with matching first and second derivatives, using zero endpoint curvature to select a unique spline.
If the data are exact samples of a sufficiently smooth function $f$, the polynomial interpolation error satisfies
$$ f(q)-P(q)=\frac{f^{(n)}(\xi)}{n!}\prod_{i=0}^{n-1}(q-x_i) $$
for some $\xi$ in the smallest interval containing the nodes and query. This is not an available numerical bound unless the derivative is bounded independently. The nodal product explains why node placement matters. Spline convergence bounds depend on mesh regularity, smoothness, and compatible boundary information; a natural endpoint condition should not be assumed to give a fourth-order global approximation for every smooth function with nonzero endpoint curvature.
Variants, Pitfalls, and Optimizations
Avoid confusing representation with the interpolation model. Switching from direct Lagrange products to barycentric Lagrange can improve evaluation, but it leaves the polynomial unchanged. Switching to a natural spline changes the model. A stable evaluator cannot eliminate oscillation inherent in a chosen high-degree interpolating polynomial.
Runge's example makes this visible. For $f(x)=1/(1+25x^2)$, use $11$ equally spaced nodes on $[-1,1]$. At $q=0.94$, the degree-at-most-ten polynomial is about $1.958952$, while the function value is about $0.043309$. The natural spline is about $0.043824$. All interpolants still meet their knot values. The large polynomial error near the endpoints is a node-placement and model issue, not disagreement between Lagrange and Newton in exact arithmetic.
If node placement is controllable, Chebyshev-distributed nodes can reduce the endpoint oscillation associated with equally spaced high-degree interpolation. Piecewise low-degree methods are another option. If nodes are fixed measurements, changing them is not simply an implementation detail.
Specify boundary conditions. Natural means zero endpoint second derivative, not zero first derivative or a guarantee of a straight endpoint interval. Clamped splines specify endpoint slopes; periodic splines join matching endpoint behavior; not-a-knot conditions select another spline. In particular, a natural spline does not reproduce every quadratic or cubic: the natural interpolant of $x^2$ at $0,1,2$ gives $S(1/2)=5/16$, rather than $1/4$, because the quadratic's endpoint curvature is not zero. When comparing with a library, explicitly select natural boundary conditions; for example, SciPy's CubicSpline default is not-a-knot.
Do not assume shape preservation. Ordinary cubic splines can overshoot monotone data or become negative between positive knots. Piecewise linear interpolation preserves interval endpoint bounds, while a shape-preserving cubic method such as PCHIP may be a better choice when monotonicity matters. A smoothing spline or regression is often more appropriate when data contain noise: forcing exact interpolation can reproduce noise as if it were signal.
Handle duplicates and scaling deliberately. Equal nodes with unequal values cannot satisfy a single-valued interpolation function. Equal nodes with derivative information require a Hermite formulation; they are not valid denominators for these routines. Centering and scaling the horizontal coordinate can reduce arithmetic problems. Clustered nodes may also make the interpolation problem sensitive even after scaling. A floating-point pivot threshold belongs to the solve policy; it should not silently redefine distinct knots as identical.
Improve repeated work. Retain barycentric weights when only the $y$ values change, reuse the spline-system factorization when the same knots support multiple data channels, and exploit the tridiagonal system for linear-time spline construction. Newton's form supports adding a distinct knot with an additional coefficient in $O(n)$ arithmetic if an incremental interface is maintained; the supplied combined class rebuilds its representations instead. For sorted spline queries, advance through intervals once rather than binary-searching every query independently.
Treat extrapolation as a separate decision. A polynomial can be evaluated beyond its nodes, but its magnitude and sensitivity may grow rapidly. Natural boundary conditions do not justify linear extrapolation outside the domain. The spline API here rejects such queries; a different application must deliberately choose and document an extension rule.
Matching all knots does not establish between-knot accuracy, monotonicity, or safe extrapolation. Check node spacing, boundary conditions, and the data's noise level; distinguish improvements to numerical evaluation from a change in the interpolating model.
Practice Problems and Real-World Use
Begin with exact polynomials and small rational data, then test nonuniform spacing, boundary conditions, and adverse examples. In addition to knot residuals, compare the two polynomial forms and check both sides of every spline join for value, slope, and curvature continuity.
| Problem or system | Concrete task | Idea tested | Difficulty |
|---|---|---|---|
| Four-knot hand trace | Reproduce $P(1/2)=1$ and natural $S(1/2)=3/4$ | Full coefficient construction and model differences | Easy |
| Polynomial reproduction | Sample a degree-$d$ polynomial at at least $d+1$ distinct nodes | Lagrange–Newton uniqueness and exactness in exact arithmetic | Easy |
| Nonuniform calibration table | Interpolate ordered, irregularly spaced sensor values | Divided differences and interval widths without equal-grid assumptions | Medium |
| Spline join audit | Compare adjacent pieces and their first two derivatives at every interior knot | Natural-spline constraints and coefficient ordering | Medium |
| Runge experiment | Compare equally spaced and Chebyshev nodes for $1/(1+25x^2)$ | Node placement, conditioning, and endpoint oscillation | Medium |
| Animation keyframes | Compare natural, clamped, and shape-preserving curves | Endpoint behavior, smoothness, and overshoot | Medium |
| Repeated lookup channels | Build interpolants for many value arrays on one knot grid | Reusing weights or a spline-system factorization | Hard |
| Noisy sampled response | Compare exact interpolation with a justified smoothing fit | Interpolation error versus noise and model error | Hard |
For further reading, NIST's interpolation chapter develops Lagrange, barycentric, and Newton formulas and their remainder terms. SciPy's cubic spline documentation states the boundary-condition choices, while its barycentric interpolator documentation discusses polynomial representation and node-placement concerns. Match the mathematical model and boundary conditions before comparing numerical outputs.