This is a very simple FFT, I am wondering what I can do to make this faster and more memory efficient from the programming side (better data types, and maybe some tricks like unrolling loops or using the preprocessor if that is useful here), and not by using a more efficient mathematical algorithm. Obviously I would appreciate advice on best practices as well.
#include <stdio.h>
#include <vector>
#include <iostream>
#include <complex>
#include <cmath>
#include <algorithm>
#define N 1048576
#define PI 3.14159265358979323846
/*
Creating the table of all N'th roots of unity.
We use notation omega_k = e^(-2 pi i / n).
*/
template<typename U>
std::vector< std::complex<U> > rootsOfUnityCalculator() {
std::vector< std::complex<U> > table;
for (size_t k = 0; k < N; k++) {
std::complex<U> kthRootOfUnity(std::cos(-2.0 * PI * k / N), std::sin(-2.0 * PI * k / N));
table.push_back(kthRootOfUnity);
}
return table;
}
/*
Fast Fourier transform, T is the precision level, so float or double.
table is a look up table of the roots of unity. Overwrites the input.
For now only works for N a power of 2.
*/
template<typename T>
void FFT(std::complex<T>* input, const std::vector< std::complex<T> >& table, size_t n) {
if (n % 2 == 0) {
// Split up the input in even and odd components
std::complex<T>* evenComponents = new std::complex<T>[n/2];
std::complex<T>* oddComponents = new std::complex<T>[n/2];
for (size_t k = 0; k < n/2; k++) {
evenComponents[k] = input[2 * k];
oddComponents[k] = input[2 * k + 1];
}
// Transform the even and odd input
FFT(evenComponents, table, n/2);
FFT(oddComponents, table, n/2);
// Use the algorithm from Danielson and Lanczos
for (size_t k = 0; k < n/2; k++) {
std::complex<T> plusMinus = table[N / n * k] * oddComponents[k]; // omega_n^k = (omega_N^(N/n))^k = omega_N^(Nk/n)
input[k] = evenComponents[k] + plusMinus;
input[k + n/2] = evenComponents[k] - plusMinus;
}
delete[] evenComponents;
delete[] oddComponents;
} else {
// The Fourier transform on one element does not do anything, so
// nothing needed here.
}
}
int main() {
std::complex<double>* input = new std::complex<double>[N];
for (size_t k = 0; k < N; k++) {
input[k] = k;
}
const std::vector< std::complex<double> > table = rootsOfUnityCalculator<double>();
// Overwrites the input with its Fourier transform
FFT<double>(input, table, N);
delete[] input;
return 0;
}