Task 5 of 6

Smooth a Signal

Time to combine everything: a 5-tap moving average. Each output cell is the mean of signal[x−2 … x+2] — a gather over a small window of neighbors, with clamping where the window hangs off either end. This shape — loop over a fixed window, clamp, accumulate — is called a stencil, and it powers blurs, edge detectors, and physics simulations alike.

Yes, a loop inside the kernel is fine: it's 5 iterations of private arithmetic per thread, not a loop over the data. 128 threads each averaging 5 numbers is still one parallel pass.

read five, write one — always your own cell
Goal: each cell returns the average of the five values centered on it, with window indexes clamped to 0 … n−1.

Requirements

Hint 1 — the window

The five indexes are this.thread.x + d - 2 for d = 0…4: two to the left, itself, two to the right.

Hint 2 — clamp inside the loop

Each iteration:

const j = Math.max(0, Math.min(this.constants.n - 1, this.thread.x + d - 2));
sum += signal[j];
Hint 3 — sanity-check the edge

Cell 0's clamped window reads indexes 0, 0, 0, 1, 2 — so out[0] should equal (3·signal[0] + signal[1] + signal[2]) / 5.

Same idea elsewhere

Windowed sums over neighbors are stencil computations — the bread and butter of scientific codes on CUDA and ROCm, where entire papers are devoted to tiling stencils into shared memory so the window reads come from fast on-chip storage instead of DRAM.

All tasks in Thinking in Parallel

  1. Map: One Thread, One Value
  2. Gather: Read Anywhere
  3. No Scatter Allowed
  4. Life on the Edge
  5. Smooth a Signal
  6. The Two-Pass Blur

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