Task 3 of 4

Integrate the Un-integrable

e^(−x²) — the bell curve — famously has no elementary antiderivative. No substitution, no parts, no closed form. Monte Carlo doesn't care: for uniform samples on [0, 1], the average of f(x) converges to ∫₀¹ f(x) dx. Sampling beats symbolic calculus.

And here's the efficiency move over last task: instead of one kernel to evaluate and another to reduce, fuse them. Each of 256 threads walks its own 64-sample slice, evaluating e^(−x²) and accumulating in one pass — 16,384 evaluations, one launch, 256 numbers back.

no antiderivative, no problem — average enough heights and it’s the area
Goal: make each thread return the sum of e^(−x²) over its 64-sample slice of samples, so the logged mean lands on ≈ 0.7468.

Requirements

Hint 1 — mean value, not area sampling

No darts this time: the estimator is just the average height of the curve, (1/N) Σ f(xᵢ), times the interval width (here 1). You only need f, not a hit test.

Hint 2 — one line changes

The loop skeleton is last task's reduction. Swap what you accumulate:

const x = xs[base + i];
sum += Math.exp(-x * x);

Same idea elsewhere

Fusing the map into the reduction halves the memory traffic — the same reasoning behind kernel fusion in CUDA and ROCm, and behind doing per-workgroup sums in a single WebGPU compute pass instead of two. Bandwidth, not arithmetic, is usually the bill.

All tasks in Monte Carlo Methods

  1. Darts at a Quarter Circle
  2. Reduce 65,536 Hits to π
  3. Integrate the Un-integrable
  4. Price an Option

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