簡體   English   中英

將 FMA 指令用於 FFT 算法

[英]Using FMA instructions for an FFT algorithm

我有一些 C++ 代碼隨着時間的推移已經成為一個有點有用的 FFT 庫,並且使用 SSE 和 AVX 指令使其運行得非常快。 誠然,這一切都僅基於 radix-2 算法,但它仍然成立。 我最近最想從頭開始是使蝴蝶計算與 FMA 指令一起工作。 基本的基數 2 蝴蝶由 4 個乘法和 6 個加法或減法組成。 一種簡單的方法是用 2 個 FMA 指令替換 2 個加法和減法以及 2 個乘法,從而產生數學上相同的蝴蝶,但顯然有更好的方法來做到這一點:

https://books.google.com/books?id=2HG0DwAAQBAJ&pg=PA56&lpg=PA56&dq=radix+2+fft+fma&source=bl&ots=R5XDWyYBVv&sig=ACfU3U0S2n1hcgiP63LTKMxI5Oc85eEZaQ&hl=en&sa=X&ved=2ahUKEwiz_I3PsrToAhVoHzQIHYmVDGIQ6AEwDXoECAoQAQ#v=onepage&q=radix%202%20fft% 20fma&f=假

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 個加法、減法和乘法,前提是旋轉因子的虛部除以實部。 部分文字為“注意 cr1 != 0”。 簡而言之,這基本上是我的問題。 數學似乎對所有旋轉因子都有效,除非真正的旋轉因子為零,在這種情況下,我們最終除以零。 在這里效率絕對至關重要,當 cr1 == 0 時將代碼分支到不同的蝴蝶不是一個好的選擇,尤其是當我們使用 SIMD 一次處理多個旋轉和蝴蝶時,其中可能只有 cr1 == 的一個元素0. 我的直覺告訴我應該是這樣,當 cr1 == 0,cr1 和 ci1 應該完全是其他一些值,FMA 代碼仍然會產生正確的答案,但我似乎無法弄清楚這一點. 如果我能弄清楚,修改 FMA 蝴蝶的預先計算的旋轉因子將是一件相對簡單的事情,我們當然也可以避免蝴蝶開始時的除法運算。

這本書似乎暗示cr1 != 0總是正確的。 但不幸的是,情況並非總是如此(當旋轉角度為 PI/2 時)。

我不認為你可以通過調整旋轉因子來解決這個問題。 我看到的唯一選擇是使用一些非常小的數字而不是零。 它可以工作,但它很丑陋,並且在某些情況下可能會導致不准確。

可能的解決方案:

  • 將循環分成兩部分,並專門處理這個中心情況(發生除以零的情況)
  • 而不是除以cr1 ,除以ci1 ,並相應修改forumula。 這種情況仍然有一個被零除,但它會在循環的第一次迭代中發生。 因此,您必須專門處理第一次迭代而不是中心(因此只需要一個循環)。
  • 使用不同的 FMA 公式:

請注意:

zoutr(1) = u0 - u1 
         = u0 - u1 - (u0 + u1) + (u0 + u1) 
         = u0 - u1 - zoutr(0) + u0 + u1 
         = 2*u0 - zoutr(0)

因此,此操作可以在 1 FMA 中完成。

如果將u1代入zoutr(0)的表達式:

zoutr(0) = u0 + u1
         = u0 + r*cr1 - s*ci1

這可以通過 2 個 FMA 來完成。

計算zouti的方法與zoutr相同。 所以這種方式需要用到6個FMA操作,跟書上的操作量是一樣的。

(注意,這並不意味着這個變體會自動運行得更快,因為它有不同的數據依賴鏈)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM