43.5 Performance and Benchmarks

Optimize FFT with cache‑friendly access, precomputed twiddle factors, and measurement.


43.5.1 Precompute Twiddle Factors

float[] precomputeTwiddles(int N) {
  float[] w = new float[N];
  for (int k = 0; k < N/2; k++) {
    w[2*k]   = (float)Math.cos(-2*Math.PI*k/N);
    w[2*k+1] = (float)Math.sin(-2*Math.PI*k/N);
  }
  return w;
}

Use lookup instead of recomputing cos/sin in loops.


43.5.2 JMH Sketch

// Requires org.openjdk.jmh:jmh-core and jmh-generator-annprocess
import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Thread)
public class FftBench {
  float[] data; int N = 1024;

  @Setup public void setup() {
    data = new float[N*2];
    java.util.Random r = new java.util.Random(42);
    for (int i = 0; i < N; i++) { data[2*i] = r.nextFloat(); }
  }

  @Benchmark public void fft() { fftRadix2(data.clone(), N); }
}

43.5.3 Tuning

  • Use lookup tables for twiddles
  • Minimize memory allocations in hot paths
  • Consider Vector API for butterfly operations (if available)

43.5.4 Validation

Compare against naive DFT on small inputs; check Parseval's theorem (energy conservation):

float energy(float[] x, int N) {
  float sum = 0f;
  for (int i = 0; i < N; i++) sum += x[2*i]*x[2*i] + x[2*i+1]*x[2*i+1];
  return sum;
}