Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 提高FFT实现速度_C++_Fft - Fatal编程技术网

C++ 提高FFT实现速度

C++ 提高FFT实现速度,c++,fft,C++,Fft,我是一名编程初学者,目前正在尝试一个需要快速傅立叶变换实现的项目 迄今为止,我已成功实施了以下措施: 是否有人有任何替代方案和建议来提高程序的速度而不损失准确性 short FFTMethod::FFTcalc(short int dir,long m,double *x,double *y) { long n,i,i1,j,k,i2,l,l1,l2; double c1,c2,tx,ty,t1,t2,u1,u2,z; /* Calculate the number of points */

我是一名编程初学者,目前正在尝试一个需要快速傅立叶变换实现的项目

迄今为止,我已成功实施了以下措施:

是否有人有任何替代方案和建议来提高程序的速度而不损失准确性

short FFTMethod::FFTcalc(short int dir,long m,double *x,double *y)
{
long n,i,i1,j,k,i2,l,l1,l2;
double c1,c2,tx,ty,t1,t2,u1,u2,z;

/* Calculate the number of points */
n = 1;
for (i=0;i<m;i++) 
    n *= 2;

/* Do the bit reversal */
i2 = n >> 1;
j = 0;
for (i=0;i<n-1;i++) {
  if (i < j) {
     tx = x[i];
     ty = y[i];
     x[i] = x[j];
     y[i] = y[j];
     x[j] = tx;
     y[j] = ty;
  }
  k = i2;
  while (k <= j) {
     j -= k;
     k >>= 1;
  }
  j += k;
}

/* Compute the FFT */
c1 = -1.0; 
c2 = 0.0;
l2 = 1;
for (l=0;l<m;l++) {
   l1 = l2;
   l2 <<= 1;
   u1 = 1.0; 
   u2 = 0.0;
   for (j=0;j<l1;j++) {
     for (i=j;i<n;i+=l2) {
        i1 = i + l1;
        t1 = u1 * x[i1] - u2 * y[i1];
        t2 = u1 * y[i1] + u2 * x[i1];
        x[i1] = x[i] - t1; 
        y[i1] = y[i] - t2;
        x[i] += t1;
        y[i] += t2;
     }
     z =  u1 * c1 - u2 * c2;
     u2 = u1 * c2 + u2 * c1;
     u1 = z;
   }
   c2 = sqrt((1.0 - c1) / 2.0);
   if (dir == 1) 
     c2 = -c2;
     c1 = sqrt((1.0 + c1) / 2.0);
  }

/* Scaling for forward transform */
if (dir == 1) {
   for (i=0;i<n;i++) {
      x[i] /= n;
      y[i] /= n;
   }
 } 


   return(1);
}
short-FFTMethod::FFTcalc(short-int-dir,long-m,double*x,double*y)
{
长n,i,i1,j,k,i2,l,l1,l2;
双c1,c2,tx,ty,t1,t2,u1,u2,z;
/*计算点数*/
n=1;
对于(i=0;i>1;
j=0;
对于(i=0;i=1;
}
j+=k;
}
/*计算FFT*/
c1=-1.0;
c2=0.0;
l2=1;

对于(l=0;l虽然我现在不能给您一个性能提示,但我想为您的优化提供一些建议,这些建议太长,无法发表评论:

  • 如果您还没有这样做,那么现在就为代码编写一些正确性测试。简单的测试如“对这个数组进行FFT,看看结果是否与我提供的结果匹配”就足够了,但是在优化代码之前,您需要一个坚定的、自动化的单元测试来确认优化后的代码是正确的

  • 然后分析你的代码,看看实际的瓶颈在哪里(i=j;i这看起来像是一本旧教科书中的基本基数-2 FFT实现。根据许多因素,几十年前有许多关于以各种方式优化FFT的论文。例如,您的数据是否小于CPU缓存


    添加:例如,如果数据向量加上一个系数表将适合CPU dcache,和/或如果乘法比CPU上的内存访问慢得多,那么预计算旋转因子表可能会减少重复使用FFT的总循环计数。但如果不是,预计算可能会更慢。Benchmark.YMMV。

    我可以推荐尝试以下几点:

  • 不要交换输入元素,而是计算位反转索引。这将节省大量内存读取和写入
  • 如果你正在做许多相同大小的FFT,那么预先计算系数。这将节省一些计算
  • 使用基数-4 FFT而不是基数-2。这将减少内部循环中的迭代次数

  • 当然,最终的答案可以通过分析代码来找到。

    我最近在Eric Postdischil的网站上找到了这个优秀的PDF。我自己开发了几个FFT,我知道与商业库竞争有多难。相信我,如果你的FFT只比Intel或FFTW慢4倍,而不是40倍,你就做得很好了!不过你可以竞争e、 这就是方法

    为了总结这篇文章,作者指出Radix2 FFT简单但效率低下,最有效的构造是radix4 FFT。更有效的方法是Radix8,但这通常不适合CPU上的寄存器,因此首选radix4

    FFT可以分阶段构造,所以要计算1024点FFT,您可以执行10个阶段的Radix2 FFT(如2^10-1024),或5个阶段的Radix4 FFT(4^5=1024)。如果您选择,您甚至可以按8*4*4*2的阶段计算1024点FFT。阶段越少,意味着对内存的读写越少(FFT性能的瓶颈是内存带宽),因此必须动态选择基数4、8或更高。Radix4阶段特别有效,因为所有权重均为1+0i、0+1i、-1+0i、0-1i,并且可以编写Radix4蝶形代码以完全适合缓存

    第二,FFT中的每个阶段都不相同。第一阶段的权重都等于1+0i。计算此权重甚至乘以它都没有意义,因为它是一个复数乘以1,因此第一阶段可以在没有权重的情况下执行。最后一阶段也可以不同地处理,并可用于执行中的抽取时间(位反转)。Eric Postphil的文档涵盖了所有这些

    权重可以预计算并存储在表中。在x86硬件上,每个Sin/cos计算大约需要100-150个周期,因此预计算这些周期可以节省10-20%的总计算时间,因为在这种情况下,内存访问比CPU计算快。使用快速算法一次计算sincos尤其有益(注意cos等于sqrt(1.0-sine*sine),或者使用表查找,cos只是正弦的相移)

    最后,一旦您有了超级精简的FFT实现,您就可以利用SIMD矢量化在蝶形例程中计算每个周期的4倍浮点或2倍双浮点运算,以实现100-300%的速度提升。考虑到以上所有因素,您将拥有一个非常流畅和快速的FFT


    更进一步,您可以通过针对特定处理器架构提供不同的FFT级实现来执行动态优化。缓存大小、寄存器计数、SSE/SSE2/3/4指令集等因每台机器而异,因此选择“一刀切”的方法通常会被目标例程打败。例如,在FFTW中,许多smaller size FFT是针对特定体系结构的高度优化的展开(无循环)实现。通过组合这些较小的构造(如RadixN例程),您可以为手头的任务选择最快和最好的例程。

    除非您需要自己编写以供理解,否则FFTW()是一个很棒的库,它是一种自我调整、超快速、可靠的实现,你可以从C++调用它(很好)。我非常喜欢FFTReal。为什么你要编写自己的实现,而不是使用数不清的库中的一个,这些库可能都更快、测试更好、更准确,并且有更多的功能?也看看KissFFT:-它是完全免费的,而FFTW对GPL项目以外的任何东西都有令人讨厌的许可问题。你在乎吗关于-2^n大小的输入?是的,你是对的@hotpaw2,我参考了一本叫做C中的数字食谱的书,因为我发现这是最好的开始。然而,这只是第一次尝试,我做到了