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;
}