我有一些C ++代码,随着时间的流逝,它已经变成了一些有用的FFT库,并且使用SSE和AVX指令使其运行得相当快。当然,它们全都基于radix-2算法,但仍然有效。我最新的尝试是使蝴蝶运算符合fma指令。基数为2的基本蝴蝶由4个乘法和6个加法或减法组成。一种简单的方法是用2条fma指令替换2个加法和减法以及2个乘法,从而产生数学上相同的蝶形图,但是显然有更好的方法:
ci1 = ci1 / cr1
u0 = zinr(0)
v0 = zini(0)
r = zinr(1)
s = sini(1)
u1 = r - s * ci1
v1 = r * ci1 + s
zoutr(0) = u0 + u1 * cr1
zouti(0) = v0 + v1 * cr1
zoutr(1) = u0 - u1 * cr1
zouti(1) = v0 - v1 * cr1
如果旋转因子的虚部除以实部,则作者用6个fma替换了所有10个加法器,子项和mults。文本的部分内容为“请注意,cr1!= 0”。简而言之,这实际上是我的问题。对于所有旋转因子,数学似乎都像广告中所述的那样起作用,除非当实际旋转为零时,在这种情况下,我们最终除以零。在这里效率至关重要的地方,当cr1 == 0时将代码分支到另一只蝴蝶不是一个好选择,尤其是当我们使用SIMD一次处理多个旋转和蝴蝶时,其中cr1 ==的一个元素0。我的直觉告诉我应该是这种情况,即当cr1 == 0时,cr1和ci1应该完全是其他一些值,fma代码仍将得出正确的答案,但我似乎无法弄清楚。如果我能弄清楚,修改fma蝴蝶的预先计算的旋转因子将是相对简单的事情,当然,我们也可以避免在蝴蝶开始时进行除法运算。