实数快速傅里叶变换

巧了我就是萌 提交于 2020-02-08 01:41:54

实数FFT可以利用变换的对称性或快速哈特莱变换来减少乘法运算,理论上乘法运算量可以减少约一半,然而在目前的计算机上实际运算时间确更长。

 

1、测试代码

(1)利用FFT直接计算实数FFT变换

void FFT1(Complex Xn[], int R2N, double data[], int N)
{
    //赋值
    for (int i = 0; i < N; i++)
    {
        Xn[i] = data[i];
    }
    //补零
    memset(Xn + N, 0, (R2N - N) * sizeof(Complex));
    FFT(Xn, R2N);
}

(2)利用哈特莱变换换算FFT

void FFT2(Complex Xn[], int R2N, double data[], int N)
{
    double *Yn = reinterpret_cast<double*>(Xn);
    int N2 = R2N >> 1;
 
    //赋值
    memcpy(Yn, data, N * sizeof(double));
    memset(Yn + N, 0, (R2N - N) * sizeof(double));
    //哈特莱变换
    FHT(Yn, R2N);
    //后半部分
    for (int i = 1; i < N2; i++)
    {
        Xn[R2N - i]._Val[0] = (Yn[i] + Yn[R2N - i]) / 2;
        Xn[R2N - i]._Val[1] = (Yn[i] - Yn[R2N - i]) / 2;
    }
    Xn[0] = Yn[0];
    Xn[N2] = Yn[N2];
    //前半部分
    for (int i = 1; i < N2; i++)
    {
        Xn[i]._Val[0] = Xn[R2N - i]._Val[0];
        Xn[i]._Val[1] = -Xn[R2N - i]._Val[1];
    }
}

(3)测试代码

#define SIZE 4194304

int main()
{
    Complex *Xn = new Complex[SIZE];
    double *Yn = new double[SIZE];

for (int i = 0; i < SIZE; i++)
 {
        Yn[i] = i + 1;
 }

    DWORD t = GetTickCount();

    //FFT1(Xn, SIZE, Yn, SIZE - 100);
    //FFT2(Xn, SIZE, Yn, SIZE - 100);
    t = GetTickCount() - t;

    printf("%ld\n", t);
    
    delete[] Xn;
    delete[] Yn;

return 0;
}

2、测试结果

FFT1运行10次时间:2641,2641,2672,2641,2610,2688,2688,2641,2640,2828

FFT2运行10次时间:3234,3203,3172,3172,3250,3219,3063,3187,3219,3250

对比可见,直接利用复数FFT算法所用时间较少,应该与程序结构有关。FFT1虽然乘法运算量较多,但结构简单,运算效率较高;FFT2虽然乘法运算量较少,但结构相对复杂,运行效率较低。由此可见,在数值计算程序设计时不光要考虑运算量与计算精度,算法结构也是不容忽视的问题。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!