private static void TransformBluestein(Complex[] data)
{
int n = data.Length;
int m = HighestOneBit(n * 2 + 1) << 1;
// Trignometric tables
var cosTable = new double[n];
var sinTable = new double[n];
for (int i = 0; i < cosTable.Length; i++)
{
int j = (int)((long)i * i % (n * 2)); // This is more accurate than j = i * i
cosTable[i] = Math.Cos(Math.PI * j / n);
sinTable[i] = Math.Sin(Math.PI * j / n);
}
// Temporary vectors and preprocessing
var areal = new double[m];
var aimag = new double[m];
for (int i = 0; i < data.Length; i++)
{
double re = data[i].Real;
double im = data[i].Imaginary;
areal[i] = +re * cosTable[i] + im * sinTable[i];
aimag[i] = -re * sinTable[i] + im * cosTable[i];
}
var breal = new double[m];
var bimag = new double[m];
breal[0] = cosTable[0];
bimag[0] = sinTable[0];
for (int i = 1; i < cosTable.Length; i++)
{
breal[i] = breal[m - i] = cosTable[i];
bimag[i] = bimag[m - i] = sinTable[i];
}
// Convolution
var creal = new double[m];
var cimag = new double[m];
Convolve(areal, aimag, breal, bimag, creal, cimag);
// Postprocessing
for (int i = 0; i < data.Length; i++)
{
double re = +creal[i] * cosTable[i] + cimag[i] * sinTable[i];
double im = -creal[i] * sinTable[i] + cimag[i] * cosTable[i];
data[i] = new Complex(re, im);
}
}