# Reduce 65,536 Hits to π

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

Last task summed the verdicts with a JavaScript loop — fine for 4,096 darts,
wasteful for 65,536 and absurd for a billion. The GPU answer is a
**parallel reduction**: don't ship every verdict home, ship
*partial sums*. A second kernel with 256 threads gives each thread its own
256-verdict slice to total, collapsing 65,536 numbers to 256 in one launch.

Thread `t` owns the slice starting at `t * 256` — a statically
bounded `for` loop walks it. JavaScript then folds the 256 partials into the
final count, and `4 × hits / 65536` is your π.

## Goal

**Goal:** complete the `partialSums` kernel so each of its
256 threads returns the sum of its own 256-element slice of `hits`, then log
the π estimate.

## Requirements

- Kernel 1 (`inside`) is last task's dart test — leave it as is
- In `partialSums`, thread `x` starts at `this.thread.x * 256`
- Loop `i = 0…255` and accumulate `hits[base + i]`
- Total the 256 partials in JavaScript and log `4 * total / 65536`

## Hint 1 — who sums what

Thread 0 sums `hits[0…255]`, thread 1 sums `hits[256…511]`,
and so on. The starting offset is `this.thread.x * 256`.

## Hint 2 — the loop

```js
const base = this.thread.x * 256;
let sum = 0;
for (let i = 0; i < 256; i++) {
  sum += hits[base + i];
}
return sum;
```

The bound is a literal, so gpu.js can unroll it safely.

## Same idea elsewhere

Reduction is *the* fundamental pattern of GPU computing — CUDA has warp
shuffles and the CUB library for it, Metal has SIMD-group reductions, WebGPU builds them
from workgroup shared memory. Chunked partial sums like yours are always the first rung.

## Starter code

```js
// 65,536 darts. Kernel 1 judges them; kernel 2 sums them — in parallel.
const gpu = new GPU({ mode });

const inside = gpu.createKernel(function (xs, ys) {
  const x = xs[this.thread.x];
  const y = ys[this.thread.x];
  if (x * x + y * y <= 1) {
    return 1;
  }
  return 0;
}, { output: [65536] });

const partialSums = gpu.createKernel(function (hits) {
  // TODO: sum THIS thread's 256-element slice of hits.
  // Slice start: this.thread.x * 256.
  return hits[this.thread.x];
}, { output: [256] });

const hits = await inside(xs, ys);
const partials = await partialSums(hits);

let total = 0;
for (let i = 0; i < partials.length; i++) total += partials[i];
console.log('π ≈', (4 * total) / 65536);
```

---

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

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