private static void TransformRadix2(Complex[] complex)
{
int n = complex.Length;
int levels = (int)Math.Floor(Math.Log(n, 2));
if (1 << levels != n)
throw new ArgumentException("Length is not a power of 2");
// TODO: keep those tables in memory
var cosTable = new double[n / 2];
var sinTable = new double[n / 2];
for (int i = 0; i < n / 2; i++)
{
cosTable[i] = Math.Cos(2 * Math.PI * i / n);
sinTable[i] = Math.Sin(2 * Math.PI * i / n);
}
// Bit-reversed addressing permutation
for (int i = 0; i < complex.Length; i++)
{
int j = unchecked((int)((uint)Reverse(i) >> (32 - levels)));
if (j > i)
{
var temp = complex[i];
complex[i] = complex[j];
complex[j] = temp;
}
}
// Cooley-Tukey decimation-in-time radix-2 FFT
for (int size = 2; size <= n; size *= 2)
{
int halfsize = size / 2;
int tablestep = n / size;
for (int i = 0; i < n; i += size)
{
for (int j = i, k = 0; j < i + halfsize; j++, k += tablestep)
{
int h = j + halfsize;
double re = complex[h].Real;
double im = complex[h].Imaginary;
double tpre = +re * cosTable[k] + im * sinTable[k];
double tpim = -re * sinTable[k] + im * cosTable[k];
double rej = complex[j].Real;
double imj = complex[j].Imaginary;
complex[h] = new Complex(rej - tpre, imj - tpim);
complex[j] = new Complex(rej + tpre, imj + tpim);
}
}
// Prevent overflow in 'size *= 2'
if (size == n)
break;
}
}