Task 5 of 5

There and Back Again

A transform earns the name by being reversible. The inverse DFT is the forward one with two edits: the exponent's sign flips to +, and the whole thing is divided by n. Both edits are load-bearing, and both are where people go wrong — forget the 1/n and your signal comes back 256 times too loud; leave the sign negative and it comes back time-reversed, which is a spectacular way to fail a test that only checks sample 0.

Summing complex terms means real arithmetic on pairs. With c = cos(angle) and s = sin(angle), one term of (re + i·im) · (c + i·s) is:

real      += re * c - im * s;
imaginary += re * s + im * c;

The shapes line up for free. output: [n, 2] hands back exactly the [2][n] nested array a kernel wants as input — spectrum[0][k] real, spectrum[1][k] imaginary — so the forward transform's result drops into the inverse with nothing in between. The original signal is real, so plane 1 of the round trip should come back as float noise: that residue is a free correctness check.

Goal: write the inverse transform — output: [256, 2], taking the [2][256] spectrum — and confirm that transforming signal and transforming it back recovers all 256 samples.

Requirements

Hint 1 — the loop runs the other way round

The forward kernel's thread owned a bin and looped over samples. Here the thread owns a sample and loops over bins, so this.thread.x is i and the loop variable is k:

const angle = 2 * Math.PI * k * this.thread.x / this.constants.n;
Hint 2 — the two planes of the answer

Same branch as the forward transform, over the complex product:

const c = Math.cos(angle);
const s = Math.sin(angle);
if (this.thread.y === 0) acc += spectrum[0][k] * c - spectrum[1][k] * s;
else acc += spectrum[0][k] * s + spectrum[1][k] * c;
Hint 3 — the scaling

return acc / this.constants.n; — once, on the finished sum, not inside the loop. Forward does not scale, inverse divides by n; put the 1/n on the wrong side and the round trip is off by a factor of 65,536.

Same idea elsewhere

The 1/n is a convention, not a law, and libraries disagree loudly about it: FFTW computes an unnormalised inverse and leaves the scaling to you, numpy puts 1/n on ifft, and cuFFT documents its own choice per plan — which is why "my round trip is n times too big" is one of the most-asked FFT questions on every platform. The sign of the exponent is equally conventional; what is not optional is that the forward and inverse pair disagree about it.

All tasks in The DFT, Honestly

  1. One Bin, One Thread
  2. One Number Is Not Enough
  3. Every Bin, One Thread Each
  4. Magnitude, Phase and the Mirror
  5. There and Back Again

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