# Integrate the Un-integrable

*Task 3 of 4 · [Monte Carlo Methods](https://gpu.rocks/learn/monte-carlo-methods-9ea19810.md) · GPU.js Learn*

`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.

## Figures

- **no antiderivative, no problem — average enough heights and it’s the area**

## Goal

**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

- Thread `x` owns the slice starting at `this.thread.x * 64`
- Evaluate `Math.exp(-x * x)` for each sample — inside the loop, inside the kernel
- Return the slice sum; JavaScript divides the grand total by 16384

## 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:

```js
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.

## Starter code

```js
// ∫₀¹ e^(−x²) dx has no closed form. Estimate it: average f over
// 16,384 seeded samples — 256 threads × 64 samples each, fused map+reduce.
const gpu = new GPU({ mode });

const partials = gpu.createKernel(function (xs) {
  const base = this.thread.x * 64;
  let sum = 0;
  for (let i = 0; i < 64; i++) {
    const x = xs[base + i];
    // TODO: accumulate f(x) = e^(−x²) — not x itself.
    sum += x;
  }
  return sum;
}, { output: [256] });

const sums = await partials(samples);

let total = 0;
for (let i = 0; i < sums.length; i++) total += sums[i];
console.log('∫₀¹ e^(−x²) dx ≈', total / 16384, '(truth ≈ 0.746824)');
```

---

Interactive version: https://gpu.rocks/learn/monte-carlo-methods-9ea19810/3

[Previous task](https://gpu.rocks/learn/monte-carlo-methods-9ea19810/2.md) · [Next task](https://gpu.rocks/learn/monte-carlo-methods-9ea19810/4.md)
