diff --git a/src/main/java/com/thealgorithms/maths/Neville.java b/src/main/java/com/thealgorithms/maths/Neville.java new file mode 100644 index 000000000000..ca45f2e8a042 --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/Neville.java @@ -0,0 +1,61 @@ +package com.thealgorithms.maths; + +import java.util.HashSet; +import java.util.Set; + +/** + * In numerical analysis, Neville's algorithm is an algorithm used for + * polynomial interpolation. Given n+1 points, there is a unique polynomial of + * degree at most n that passes through all the points. Neville's algorithm + * computes the value of this polynomial at a given point. + * + *

+ * Wikipedia: https://en.wikipedia.org/wiki/Neville%27s_algorithm + * + * @author Mitrajit Ghorui(KeyKyrios) + */ +public final class Neville { + + private Neville() { + } + + /** + * Evaluates the polynomial that passes through the given points at a + * specific x-coordinate. + * + * @param x The x-coordinates of the points. Must be the same length as y. + * @param y The y-coordinates of the points. Must be the same length as x. + * @param target The x-coordinate at which to evaluate the polynomial. + * @return The interpolated y-value at the target x-coordinate. + * @throws IllegalArgumentException if the lengths of x and y arrays are + * different, if the arrays are empty, or if x-coordinates are not unique. + */ + public static double interpolate(double[] x, double[] y, double target) { + if (x.length != y.length) { + throw new IllegalArgumentException("x and y arrays must have the same length."); + } + if (x.length == 0) { + throw new IllegalArgumentException("Input arrays cannot be empty."); + } + + // Check for duplicate x-coordinates to prevent division by zero + Set seenX = new HashSet<>(); + for (double val : x) { + if (!seenX.add(val)) { + throw new IllegalArgumentException("Input x-coordinates must be unique."); + } + } + + int n = x.length; + double[] p = new double[n]; + System.arraycopy(y, 0, p, 0, n); // Initialize p with y values + + for (int k = 1; k < n; k++) { + for (int i = 0; i < n - k; i++) { + p[i] = ((target - x[i + k]) * p[i] + (x[i] - target) * p[i + 1]) / (x[i] - x[i + k]); + } + } + + return p[0]; + } +} diff --git a/src/test/java/com/thealgorithms/maths/NevilleTest.java b/src/test/java/com/thealgorithms/maths/NevilleTest.java new file mode 100644 index 000000000000..234fb2d65ce4 --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/NevilleTest.java @@ -0,0 +1,69 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +public class NevilleTest { + + @Test + public void testInterpolateLinear() { + // Test with a simple linear function y = 2x + 1 + // Points (0, 1) and (2, 5) + double[] x = {0, 2}; + double[] y = {1, 5}; + // We want to find y when x = 1, which should be 3 + double target = 1; + double expected = 3.0; + assertEquals(expected, Neville.interpolate(x, y, target), 1e-9); + } + + @Test + public void testInterpolateQuadratic() { + // Test with a quadratic function y = x^2 + // Points (0, 0), (1, 1), (3, 9) + double[] x = {0, 1, 3}; + double[] y = {0, 1, 9}; + // We want to find y when x = 2, which should be 4 + double target = 2; + double expected = 4.0; + assertEquals(expected, Neville.interpolate(x, y, target), 1e-9); + } + + @Test + public void testInterpolateWithNegativeNumbers() { + // Test with y = x^2 - 2x + 1 + // Points (-1, 4), (0, 1), (2, 1) + double[] x = {-1, 0, 2}; + double[] y = {4, 1, 1}; + // We want to find y when x = 1, which should be 0 + double target = 1; + double expected = 0.0; + assertEquals(expected, Neville.interpolate(x, y, target), 1e-9); + } + + @Test + public void testMismatchedArrayLengths() { + double[] x = {1, 2}; + double[] y = {1}; + double target = 1.5; + assertThrows(IllegalArgumentException.class, () -> Neville.interpolate(x, y, target)); + } + + @Test + public void testEmptyArrays() { + double[] x = {}; + double[] y = {}; + double target = 1; + assertThrows(IllegalArgumentException.class, () -> Neville.interpolate(x, y, target)); + } + + @Test + public void testDuplicateXCoordinates() { + double[] x = {1, 2, 1}; + double[] y = {5, 8, 3}; + double target = 1.5; + assertThrows(IllegalArgumentException.class, () -> Neville.interpolate(x, y, target)); + } +}