BARYCENTRIC_INTERP

Overview

The BARYCENTRIC_INTERP function performs polynomial interpolation using the barycentric formulation of Lagrange interpolation. Given a set of data points, it constructs a polynomial that passes exactly through all points, then evaluates that polynomial at specified locations. This technique is widely used in numerical analysis for curve fitting, data approximation, and function reconstruction.

Barycentric interpolation is a reformulation of Lagrange polynomial interpolation that offers improved numerical stability and computational efficiency. The method expresses the interpolating polynomial using pre-computed barycentric weights w_j, defined as:

w_j = \frac{1}{\prod_{m \neq j}(x_j - x_m)}

The interpolated value at any point x is then computed using the second (true) barycentric form:

L(x) = \frac{\sum_{j=0}^{k} \frac{w_j}{x - x_j} y_j}{\sum_{j=0}^{k} \frac{w_j}{x - x_j}}

This formulation avoids explicit computation of the polynomial coefficients, which enhances numerical stability. The algorithm is numerically stable because potential cancellation errors in the terms (x - x_j) appear in both numerator and denominator, effectively canceling out.

This implementation uses SciPy’s barycentric_interpolate function from the scipy.interpolate module. The source code is available in the SciPy GitHub repository.

Important consideration: While barycentric interpolation is numerically stable, polynomial interpolation itself can be ill-conditioned for certain node distributions due to Runge’s phenomenon, which causes large oscillations at the edges of the interval. For best results with many interpolation points, consider using Chebyshev nodes (points at \cos(i\pi/n)) rather than equally spaced points.

This example function is provided as-is without any representation of accuracy.

Excel Usage

=BARYCENTRIC_INTERP(xi, yi, x)
  • xi (list[list], required): The x-coordinates of the data points
  • yi (list[list], required): The y-coordinates of the data points
  • x (list[list], required): The x-coordinates at which to evaluate

Returns (list[list]): A 2D list (column vector) of interpolated values, or an error message (str) if invalid.

Examples

Example 1: Linear interpolation between two points

Inputs:

xi yi x
0 0 0.5
1 1

Excel formula:

=BARYCENTRIC_INTERP({0;1}, {0;1}, {0.5})

Expected output:

Result
0.5

Example 2: Quadratic polynomial at single point

Inputs:

xi yi x
0 0 1.5
1 1
2 4

Excel formula:

=BARYCENTRIC_INTERP({0;1;2}, {0;1;4}, {1.5})

Expected output:

Result
2.25

Example 3: Evaluate at multiple points

Inputs:

xi yi x
1 1 1.5
2 4 2.5
3 9

Excel formula:

=BARYCENTRIC_INTERP({1;2;3}, {1;4;9}, {1.5;2.5})

Expected output:

Result
2.25
6.25

Example 4: Evaluation at exact data point

Inputs:

xi yi x
0 1 1
1 2
2 5
3 10

Excel formula:

=BARYCENTRIC_INTERP({0;1;2;3}, {1;2;5;10}, {1})

Expected output:

Result
2

Python Code

import math
from scipy.interpolate import barycentric_interpolate as scipy_barycentric_interpolate

def barycentric_interp(xi, yi, x):
    """
    Interpolating polynomial for a set of points using barycentric interpolation.

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.barycentric_interpolate.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        xi (list[list]): The x-coordinates of the data points
        yi (list[list]): The y-coordinates of the data points
        x (list[list]): The x-coordinates at which to evaluate

    Returns:
        list[list]: A 2D list (column vector) of interpolated values, or an error message (str) if invalid.
    """
    def to2d(val):
        """Convert scalar or 2D list to 2D list format."""
        return [[val]] if not isinstance(val, list) else val

    def flatten(arr):
        """Flatten a 2D list to a 1D list."""
        return [item for sublist in arr for item in sublist]

    def validate_numeric_list(arr, name):
        """Validate that a 2D list contains only finite numeric values."""
        if not isinstance(arr, list):
            return f"Error: {name} must be a list."
        if not arr:
            return f"Error: {name} cannot be empty."
        for i, row in enumerate(arr):
            if not isinstance(row, list):
                return f"Error: {name} must be a 2D list."
            for j, val in enumerate(row):
                if not isinstance(val, (int, float)):
                    return f"Error: {name}[{i}][{j}] must be numeric."
                if math.isnan(val) or math.isinf(val):
                    return f"Error: {name}[{i}][{j}] must be finite."
        return None

    try:
        # Normalize inputs to 2D lists
        xi = to2d(xi)
        yi = to2d(yi)
        x = to2d(x)

        # Validate inputs
        error = validate_numeric_list(xi, "xi")
        if error:
            return error
        error = validate_numeric_list(yi, "yi")
        if error:
            return error
        error = validate_numeric_list(x, "x")
        if error:
            return error

        # Flatten to 1D arrays
        xi_flat = flatten(xi)
        yi_flat = flatten(yi)
        x_flat = flatten(x)

        # Check that xi and yi have the same length
        if len(xi_flat) != len(yi_flat):
            return "Error: xi and yi must have the same length."

        # Check minimum points requirement
        if len(xi_flat) < 1:
            return "Error: at least one data point is required."

        # Check for duplicate xi values
        if len(xi_flat) != len(set(xi_flat)):
            return "Error: xi values must be unique."

        # Call scipy.interpolate.barycentric_interpolate
        result = scipy_barycentric_interpolate(xi_flat, yi_flat, x_flat)

        # Convert result to list and validate
        if hasattr(result, '__iter__'):
            result_list = list(result)
        else:
            result_list = [result]

        # Validate all results are finite
        for i, val in enumerate(result_list):
            if not isinstance(val, (int, float)):
                return f"Error: non-numeric result at index {i}."
            if math.isnan(val) or math.isinf(val):
                return f"Error: non-finite result at index {i}."

        # Return as 2D column vector
        return [[float(val)] for val in result_list]

    except Exception as exc:
        return f"Error: {exc}"

Online Calculator