# Payoff: Mean and RMS, Fused

*Task 6 of 6 · [Reductions](https://gpu.rocks/learn/reductions-3dadc130.md) · GPU.js Learn*

The payoff. Two statistics over 4,096 values: the **mean**
(sum ÷ n) and the **RMS** — root-mean-square,
√(sum of squares ÷ n) — the standard "how big is this signal"
measure in audio and physics.

RMS needs every value squared first. The rookie move is a separate squaring kernel —
a whole extra pass over memory. The pro move is **fusion**: square each
value in the same statement that reads it, inside the partial-sum kernel. Map and
reduce, one pass over the data.

Stack the whole module: strided partials (task 2) shrink 4,096 values to 64, then a
single shared halving ladder (task 4) finishes *both* totals.

## Goal

**Goal:** compute and log the mean and the RMS of `data` —
two partial-sum kernels (one fused with squaring) plus one shared dynamic halving
ladder.

## Requirements

- `partialSums`: 64 strided partial sums of `data`, as in task 2
- `partialSquares`: same shape, but square each value *as it is read* — no separate squaring pass
- One dynamic halving-ladder kernel rides both 64-value arrays down to scalars
- `mean = total / 4096`, `rms = Math.sqrt(totalSq / 4096)` — log both

## Hint 1 — the fused body

Read once, use twice:

```js
const v = data[i * this.constants.threads + this.thread.x];
sum += v * v;
```

## Hint 2 — one ladder, two rides

The ladder kernel doesn't care what its 64 inputs mean. Wrap the driver loop
in a function and call it once with each partials array.

## Hint 3 — the whole shape

```js
const total = await ladder(await partialSums(data));
const totalSq = await ladder(await partialSquares(data));
```

then divide, square-root,
and log.

## Same idea elsewhere

Fusing the map into the reduce is a marquee optimization on every platform:
`thrust::transform_reduce` exists precisely for it, CUDA programmers
hand-fuse to halve their memory traffic, and WebGPU/Metal kernels bake the transform
into the accumulation loop. Memory bandwidth is the budget — fusion is the
discount.

## Starter code

```js
// Everything in one pipeline: partials → shared ladder → two statistics.
const gpu = new GPU({ mode });

const partialSums = gpu.createKernel(function (data) {
  // TODO: strided partial sums, exactly like task 2
  return 0;
}, { output: [64], constants: { threads: 64, chunk: 64 } });

const partialSquares = gpu.createKernel(function (data) {
  // TODO: same walk, but square each value AS you read it (fusion!)
  return 0;
}, { output: [64], constants: { threads: 64, chunk: 64 } });

// One rung, reused for both reductions.
const halve = gpu.createKernel(function (data) {
  return data[this.thread.x] + data[this.thread.x + this.output.x];
}, { dynamicOutput: true, dynamicArguments: true });

async function ladder(values) {
  let v = values;
  let n = v.length;
  while (n > 1) {
    n = n / 2;
    halve.setOutput([n]);
    v = await halve(v);
  }
  return v[0];
}

const total = await ladder(await partialSums(data));
const totalSq = await ladder(await partialSquares(data));

const mean = total / 4096;
const rms = Math.sqrt(totalSq / 4096);
console.log('mean:', mean);
console.log('rms:', rms);
```

---

Interactive version: https://gpu.rocks/learn/reductions-3dadc130/6

[Previous task](https://gpu.rocks/learn/reductions-3dadc130/5.md)
