Reference Updated July 2026 · Physics reference

Numerical Methods Cheatsheet

The numerical toolbox behind every real-time simulation on this site: ODE integrators, root finding, linear solvers, interpolation, and FFT basics. Each entry includes the formula, its error order, a stability note, and ready-to-drop-in JavaScript.

🎯 Why Numerical Methods Matter

Every physics simulation — a bouncing ball, a cloth sheet, an orbiting planet — is governed by differential equations that almost never have a closed-form solution once collisions, non-linear forces, or many interacting bodies are involved. Numerical methods turn continuous equations into discrete update rules a computer can run every frame, trading exactness for speed and controllable error.

Choosing the right method is a trade-off between three axes: accuracy (how close to the true trajectory), stability (does error blow up over time), and cost (function evaluations per step). This page collects the methods actually used across the simulations on this site, with the practical guidance that textbooks often bury.

🌀 ODE Integrators

Simulation state (position, velocity) evolves according to a first-order ODE $\dot{\mathbf{y}} = f(t, \mathbf{y})$. An integrator advances $\mathbf{y}$ from $t$ to $t+h$ using evaluations of $f$.

Explicit (Forward) Euler

Update rule — order 1 $$\mathbf{y}_{n+1} = \mathbf{y}_n + h\, f(t_n, \mathbf{y}_n)$$

The simplest integrator: one function evaluation per step, trivial to implement, but it systematically gains energy in oscillatory systems (a pendulum simulated with Euler slowly spirals outward). Local error is $O(h^2)$, global error $O(h)$.

function eulerStep(state, force, h) {
  // state = { x, v }, force(x, v) returns acceleration
  const a = force(state.x, state.v);
  state.x += h * state.v;
  state.v += h * a;
  return state;
}

Semi-implicit (Symplectic) Euler

Update rule — order 1, symplectic $$\mathbf{v}_{n+1} = \mathbf{v}_n + h\, a(\mathbf{x}_n) \qquad \mathbf{x}_{n+1} = \mathbf{x}_n + h\, \mathbf{v}_{n+1}$$

Swap the order — update velocity first, then use the new velocity to update position. Same cost as forward Euler, still only first-order accurate, but it is symplectic: energy oscillates around the true value instead of drifting away. This is the default integrator in almost every real-time game physics engine (Box2D, Cannon-es, Rapier).

function symplecticEulerStep(state, force, h) {
  const a = force(state.x, state.v);
  state.v += h * a;        // velocity first
  state.x += h * state.v;  // then position, using new v
  return state;
}

Velocity Verlet

Update rule — order 2, symplectic, time-reversible $$\mathbf{x}_{n+1} = \mathbf{x}_n + h\mathbf{v}_n + \tfrac{1}{2}h^2 a(\mathbf{x}_n)$$ $$\mathbf{v}_{n+1} = \mathbf{v}_n + \tfrac{1}{2}h\left[a(\mathbf{x}_n) + a(\mathbf{x}_{n+1})\right]$$

The workhorse of particle systems, molecular dynamics, and cloth/rope solvers. Second-order accurate, symplectic (bounded energy error), and time-reversible. Costs two acceleration evaluations per step when acceleration depends on velocity; cheaper when it doesn't.

function verletStep(state, accel, h) {
  const a0 = accel(state.x);
  state.x += h * state.v + 0.5 * h * h * a0;
  const a1 = accel(state.x);
  state.v += 0.5 * h * (a0 + a1);
  return state;
}

Runge-Kutta 4 (RK4)

Update rule — order 4, four evaluations $$k_1 = f(t_n, y_n)\qquad k_2 = f(t_n+\tfrac{h}{2}, y_n+\tfrac{h}{2}k_1)$$ $$k_3 = f(t_n+\tfrac{h}{2}, y_n+\tfrac{h}{2}k_2)\qquad k_4 = f(t_n+h, y_n+hk_3)$$ $$y_{n+1} = y_n + \tfrac{h}{6}(k_1 + 2k_2 + 2k_3 + k_4)$$

Four function evaluations per step buy fourth-order accuracy — global error $O(h^4)$ versus $O(h)$ for Euler. Excellent for smooth, non-collisional dynamics (orbital mechanics, camera paths) where you want high accuracy at a larger step size. RK4 is not symplectic: over very long integrations (millions of orbits) energy can still drift, just far more slowly than with Euler.

function rk4Step(y, t, h, f) {
  const k1 = f(t, y);
  const k2 = f(t + h / 2, add(y, scale(k1, h / 2)));
  const k3 = f(t + h / 2, add(y, scale(k2, h / 2)));
  const k4 = f(t + h, add(y, scale(k3, h)));
  return add(y, scale(
    add(add(k1, scale(k2, 2)), add(scale(k3, 2), k4)),
    h / 6
  ));
}
Integrator Order Evals/step Symplectic Best for
Forward Euler O(h) 1 No Teaching only — avoid in production
Symplectic Euler O(h) 1 Yes Game physics, particle systems
Velocity Verlet O(h²) 1–2 Yes Cloth, ropes, molecular dynamics
RK4 O(h⁴) 4 No Orbits, smooth non-collisional motion
Implicit (Backward) Euler O(h) Unconditionally stable Stiff systems (position-based dynamics, cloth solvers)

⚖ Stability & Step Size

A method is stable for a given step size $h$ if small errors do not grow unboundedly over many steps. For the test equation $\dot{y} = \lambda y$ (with $\lambda$ complex, $\text{Re}(\lambda) \le 0$), each explicit method has a bounded region of absolute stability in the complex plane $h\lambda$.

Forward Euler stability condition $$|1 + h\lambda| \le 1$$

For a damped spring-mass system with stiffness $k$ and mass $m$, this translates to a practical rule of thumb:

Explicit integrator step-size bound (stiff spring) $$h \lesssim \frac{2m}{\sqrt{km}} = \frac{2}{\omega_0}, \qquad \omega_0 = \sqrt{k/m}$$

Exceed this and a stiff spring (high k) simulated with an explicit integrator will oscillate with growing amplitude and eventually explode — the classic "jittery exploding cloth" bug. Three fixes, in order of preference:

// Fixed-timestep accumulator loop (decouples physics from render rate)
let accumulator = 0;
const FIXED_DT = 1 / 60;

function frame(now) {
  accumulator += (now - lastTime) / 1000;
  lastTime = now;
  while (accumulator >= FIXED_DT) {
    physicsStep(FIXED_DT);
    accumulator -= FIXED_DT;
  }
  render(accumulator / FIXED_DT); // interpolation alpha
  requestAnimationFrame(frame);
}
Never scale physics by frame delta alone

Multiplying accelerations by a raw, unclamped deltaTime makes your simulation non-deterministic and unstable on frame drops. Always clamp deltaTime (e.g. to 0.1s max) and prefer a fixed substep loop for anything beyond a toy demo.

🔍 Root Finding

Used for collision time-of-impact queries, inverse kinematics, and solving implicit constraint equations $g(\mathbf{x}) = 0$.

Bisection method

Guaranteed convergence, linear rate $$c = \frac{a+b}{2}, \quad \text{keep half where } \text{sign}(f)\text{ changes}$$

Requires $f(a)$ and $f(b)$ to have opposite signs. Always converges, halving the bracket each iteration — reliable but slow ($O(\log_2(\epsilon^{-1}))$ iterations for tolerance $\epsilon$).

Newton-Raphson method

Quadratic convergence near the root $$x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}$$

Converges much faster than bisection when it converges, but can diverge or cycle if the initial guess is far from the root or $f'(x_n) \approx 0$. Used heavily in continuous collision detection to refine the exact time of impact.

function newtonRaphson(f, fPrime, x0, tol = 1e-6, maxIter = 50) {
  let x = x0;
  for (let i = 0; i < maxIter; i++) {
    const fx = f(x);
    if (Math.abs(fx) < tol) return x;
    const dfx = fPrime(x);
    if (Math.abs(dfx) < 1e-12) break; // derivative too flat, bail out
    x -= fx / dfx;
  }
  return x; // best effort — caller should validate
}

Bisection vs Newton — when to use which

Method Convergence Needs derivative Guaranteed to converge
Bisection Linear No Yes (if bracketed)
Newton-Raphson Quadratic Yes (analytic or numeric) No
Secant method Superlinear (~1.618) No (approximates it) No

🔢 Linear Systems

Solving $A\mathbf{x} = \mathbf{b}$ appears throughout simulation: constraint solvers (rigid body contacts, ropes), implicit integration, and inverse kinematics Jacobians.

Gauss-Seidel iteration

Used by most real-time constraint solvers $$x_i^{(k+1)} = \frac{1}{a_{ii}}\left(b_i - \sum_{j<i} a_{ij}x_j^{(k+1)} - \sum_{j>i} a_{ij}x_j^{(k)}\right)$$

Physics engines (Box2D, Bullet, Cannon-es) solve contact and joint constraints with a handful of Gauss-Seidel (or projected Gauss-Seidel, for inequality constraints like non-penetration) iterations per frame rather than an exact solve — a few iterations of an approximate answer every frame beats one exact solve that misses the deadline.

// N Gauss-Seidel sweeps over a sparse constraint system
function solveConstraints(constraints, iterations = 10) {
  for (let iter = 0; iter < iterations; iter++) {
    for (const c of constraints) {
      c.solve(); // updates velocities in place, uses latest values
    }
  }
}

LU decomposition (dense, direct)

For small dense systems (e.g. a 3×3 or 4×4 inertia tensor solve), a direct LU decomposition is cheap and exact: factor $A = LU$ once, then solve two triangular systems per right-hand side via forward/back substitution — $O(n^3)$ to factor, $O(n^2)$ per solve.

Method Cost Best for
Gauss-Seidel / PGS O(k·nnz) Large sparse constraint systems, real-time (bounded iterations)
Conjugate Gradient O(k·nnz) Symmetric positive-definite systems (implicit cloth/FEM)
LU decomposition O(n³) Small dense systems (inertia tensors, IK Jacobians)
Cramer's rule O(n!) Never in production — only 2×2/3×3 by hand

📈 Interpolation

Linear interpolation (lerp)

lerp(a, b, t) $$\text{lerp}(a, b, t) = a + t(b - a), \quad t \in [0,1]$$

Cubic Hermite / Catmull-Rom spline

Smooth path through control points, C¹ continuous $$p(t) = \tfrac{1}{2}\Big[(2p_1) + (-p_0+p_2)t + (2p_0-5p_1+4p_2-p_3)t^2 + (-p_0+3p_1-3p_2+p_3)t^3\Big]$$

Catmull-Rom passes exactly through every control point (unlike Bézier) and is the standard choice for camera paths and procedural roads/tracks in the simulations here.

Spherical linear interpolation (slerp)

Constant angular velocity between two rotations $$\text{slerp}(q_0, q_1, t) = q_0 \left(q_0^{-1}q_1\right)^t, \quad t \in [0,1]$$

Unlike component-wise lerp of quaternions, slerp interpolates along the great-circle arc so rotation speed stays constant — essential for smooth camera and character orientation blending.

Method Continuity Passes through points? Typical use
Linear (lerp) C⁰ Yes Simple animation blending, colour fades
Catmull-Rom Yes Camera paths, procedural track/road generation
Cubic Bézier C¹ (per segment) Only endpoints Easing curves, UI motion
Slerp Constant angular speed Yes (rotations) Camera / bone rotation blending

∫ Numerical Differentiation & Integration

Central difference (derivative)

Error O(h²) — prefer over forward difference $$f'(x) \approx \frac{f(x+h) - f(x-h)}{2h}$$

Used to numerically approximate a Jacobian or normal vector (e.g. gradient of a signed-distance field) when no analytic derivative is available. The central difference cancels the first-order error term that a naive forward difference $\frac{f(x+h)-f(x)}{h}$ carries.

Trapezoidal rule (integration)

Error O(h²) per interval $$\int_a^b f(x)\,dx \approx h\left[\tfrac{1}{2}f(x_0) + f(x_1) + \dots + f(x_{n-1}) + \tfrac{1}{2}f(x_n)\right]$$

Simpson's rule (integration)

Error O(h⁴) — exact for cubics $$\int_a^b f(x)\,dx \approx \frac{h}{3}\Big[f(x_0) + 4f(x_1) + 2f(x_2) + 4f(x_3) + \dots + f(x_n)\Big]$$

Simpson's rule fits a parabola through every three points and is the cheapest big accuracy win over the trapezoidal rule for smooth integrands — useful when precomputing arc-length tables for splines (needed for constant-speed path following).

🌊 FFT Basics

The Fast Fourier Transform converts a signal from the time/space domain to the frequency domain in $O(n\log n)$ instead of the $O(n^2)$ of a naive Discrete Fourier Transform (DFT) — the backbone of ocean-wave simulation (Tessendorf/FFT ocean), audio-reactive visuals, and GPU-based fluid solvers.

Discrete Fourier Transform (definition) $$X_k = \sum_{n=0}^{N-1} x_n\, e^{-2\pi i k n / N}, \quad k = 0, \dots, N-1$$

The Cooley-Tukey FFT algorithm recursively splits the sum into even- and odd-indexed terms, halving the problem size each recursion level — hence $N$ must typically be a power of two for the classic radix-2 implementation used in most WebGL ocean shaders.

Algorithm Cost Constraint
Naive DFT O(n²) None — works for any N
Radix-2 Cooley-Tukey FFT O(n log n) N must be a power of 2
Mixed-radix FFT O(n log n) N factors into small primes

In practice, ocean and water simulations here run the FFT on a GPU compute shader (or a WebGL ping-pong render target pass) to transform a heightfield spectrum into displacement — a 256×256 grid costs roughly 16 passes of radix-2 butterflies per dimension.

📊 Error Order Quick Table

Halving the step size $h$ for a method of order $p$ reduces the error by roughly $2^p$. Use this to sanity-check a method's convergence empirically (Richardson extrapolation): halve $h$, re-run, and confirm the error drops by the expected factor.

Method Global error order Error reduction per h/2
Forward / Backward Euler O(h)
Symplectic Euler O(h)
Velocity Verlet O(h²)
Trapezoidal rule O(h²)
RK4 O(h⁴) 16×
Simpson's rule O(h⁴) 16×

⚠ Common Pitfalls

Rule of thumb

Start with symplectic Euler at a fixed 60 Hz substep for anything interactive. Reach for Verlet when you need better energy conservation (cloth, ropes, particles), and RK4 only for smooth, non-colliding trajectories where accuracy matters more than raw speed (camera paths, orbital previews).