Task 3 of 5

Softening the Singularity

Two of this task's bodies sit 0.001 apart. Plug that into 1 / r² and their mutual pull is about a million — one tick of the clock later they're flung out of the galaxy. That's not physics; it's what happens when a point-mass model meets a finite time step.

The standard fix is Plummer softening: replace with r² + ε². Far away, ε changes nothing; up close, the force flattens out instead of diverging. Bonus: the j !== i self-check becomes dead weight — your own term has dx = dy = 0, so it contributes exactly zero. Drop the branch; GPUs run happiest when every thread takes the same path.

close encounters flatten out instead of blowing up
Goal: soften the kernel — use r² + soft², drop the self-check, and return the full [ax, ay] pair.

Requirements

Hint 1 — why the guard can go

For j === i: dx and dy are 0, so the contribution is 0 · something. With soft² > 0 the denominator is never zero, so that something is a plain finite number.

Hint 2 — share the weight

Compute const w = mass[j] / (r2 * Math.sqrt(r2)); once, then ax += dx * w; ay += dy * w; — one denominator, two components.

Same idea elsewhere

Softening appears verbatim in production astrophysics codes (GADGET, Bonsai) on CUDA and ROCm clusters. It's also a lesson in GPU numerics generally: shader float math never throws — a divide-by-zero silently mints Infinity and then NaNs spread through every sum they touch, on Metal and WebGPU alike.

All tasks in N-Body Gravity

  1. The Pull of One Star
  2. Every Body Pulls on Every Body
  3. Softening the Singularity
  4. One Tick of the Clock
  5. Put It Together: 128 Bodies

This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.