43.2 Radix‑2 FFT Algorithm (Cooley–Tukey)

Radix‑2 FFT requires N = 2^m. It splits the transform into even/odd halves recursively.


43.2.1 Bit‑Reversal Permutation

In‑place FFT needs input in bit‑reversed order:

void bitReverse(float[] x, int N) {
  int bits = Integer.numberOfTrailingZeros(N);
  for (int i = 0; i < N; i++) {
    int rev = Integer.reverse(i) >>> (32 - bits);
    if (rev > i) {
      float tre = x[2*i], tim = x[2*i+1];
      x[2*i] = x[2*rev]; x[2*i+1] = x[2*rev+1];
      x[2*rev] = tre; x[2*rev+1] = tim;
    }
  }
}

43.2.2 Iterative Radix‑2 FFT

void fftRadix2(float[] x, int N) {
  bitReverse(x, N);
  for (int s = 1; s <= Math.log(N)/Math.log(2); s++) {
    int m = 1 << s;
    float wm_re = (float)Math.cos(-2*Math.PI / m);
    float wm_im = (float)Math.sin(-2*Math.PI / m);
    for (int k = 0; k < N; k += m) {
      float w_re = 1f, w_im = 0f;
      for (int j = 0; j < m/2; j++) {
        int t = k + j + m/2;
        int u = k + j;
        float t_re = w_re * x[2*t]   - w_im * x[2*t+1];
        float t_im = w_re * x[2*t+1] + w_im * x[2*t];
        x[2*t]   = x[2*u]   - t_re;
        x[2*t+1] = x[2*u+1] - t_im;
        x[2*u]   += t_re;
        x[2*u+1] += t_im;
        // update w
        float new_w_re = w_re * wm_re - w_im * wm_im;
        float new_w_im = w_re * wm_im + w_im * wm_re;
        w_re = new_w_re; w_im = new_w_im;
      }
    }
  }
}

43.2.3 Inverse FFT

Swap sign in twiddle factors and scale by 1/N:

void ifft(float[] X, int N) {
  // conjugate
  for (int i = 0; i < N; i++) X[2*i+1] = -X[2*i+1];
  fftRadix2(X, N);
  // conjugate and scale
  float scale = 1f / N;
  for (int i = 0; i < N; i++) {
    X[2*i]   *= scale;
    X[2*i+1] *= -scale;
  }
}