45.4 Numerical Methods

Implement fundamental algorithms for root finding, integration, and interpolation.


45.4.1 Newton-Raphson Root Finding

Find x where f(x) = 0 using iteration: x_{n+1} = x_n - f(x_n)/f'(x_n)

interface Func { double f(double x); double df(double x); }

double newtonRaphson(Func func, double x0, double tol, int maxIter) {
  double x = x0;
  for (int i = 0; i < maxIter; i++) {
    double fx = func.f(x);
    if (Math.abs(fx) < tol) return x;
    double dfx = func.df(x);
    if (Math.abs(dfx) < 1e-14) throw new ArithmeticException("Derivative too small");
    x = x - fx / dfx;
  }
  throw new RuntimeException("Did not converge");
}

// Example: find sqrt(2) via f(x) = x² - 2
Func sqrt2 = new Func() {
  public double f(double x) { return x*x - 2; }
  public double df(double x) { return 2*x; }
};
double root = newtonRaphson(sqrt2, 1.0, 1e-10, 100); // ~1.414

45.4.2 Bisection Method

Guaranteed convergence if f continuous and f(a)·f(b) < 0.

double bisection(java.util.function.DoubleUnaryOperator f, double a, double b, double tol) {
  double fa = f.applyAsDouble(a);
  double fb = f.applyAsDouble(b);
  if (fa * fb > 0) throw new IllegalArgumentException("f(a) and f(b) must have opposite signs");

  while (b - a > tol) {
    double c = (a + b) / 2;
    double fc = f.applyAsDouble(c);
    if (Math.abs(fc) < tol) return c;
    if (fa * fc < 0) { b = c; fb = fc; }
    else { a = c; fa = fc; }
  }
  return (a + b) / 2;
}

45.4.3 Numerical Integration (Trapezoidal Rule)

∫ₐᵇ f(x) dx ≈ h/2 · [f(a) + 2·Σf(xᵢ) + f(b)]

double trapezoid(java.util.function.DoubleUnaryOperator f, double a, double b, int n) {
  double h = (b - a) / n;
  double sum = 0.5 * (f.applyAsDouble(a) + f.applyAsDouble(b));
  for (int i = 1; i < n; i++) {
    sum += f.applyAsDouble(a + i * h);
  }
  return h * sum;
}

// Example: ∫₀¹ x² dx = 1/3
double integral = trapezoid(x -> x*x, 0, 1, 1000); // ~0.333

45.4.4 Simpson's Rule

Higher accuracy: ∫ₐᵇ f(x) dx ≈ h/3 · [f(a) + 4·Σf(odd) + 2·Σf(even) + f(b)]

double simpson(java.util.function.DoubleUnaryOperator f, double a, double b, int n) {
  if (n % 2 != 0) throw new IllegalArgumentException("n must be even");
  double h = (b - a) / n;
  double sum = f.applyAsDouble(a) + f.applyAsDouble(b);
  for (int i = 1; i < n; i++) {
    double x = a + i * h;
    sum += (i % 2 == 0 ? 2 : 4) * f.applyAsDouble(x);
  }
  return h * sum / 3;
}

45.4.5 Linear Interpolation

double lerp(double x0, double y0, double x1, double y1, double x) {
  return y0 + (y1 - y0) * (x - x0) / (x1 - x0);
}

// For tabulated data
double interpolate(double[] xs, double[] ys, double x) {
  for (int i = 0; i < xs.length - 1; i++) {
    if (x >= xs[i] && x <= xs[i+1]) {
      return lerp(xs[i], ys[i], xs[i+1], ys[i+1], x);
    }
  }
  throw new IllegalArgumentException("x out of range");
}