模板 快速傅利葉變換(FFT)

2022-05-16 11:55:45 字數 3768 閱讀 7408

參考:

如果公式炸了請去我的csdn部落格:

原文即是一篇很好的fft入門部落格,但是筆者打算為了日後的學習,則將原篇章的結構刪改增添一下,如有思路上的雷同十分正常。

「是時候開啟fft的大門了!」

1.至少知道基礎數論與一定解三角形知識(大概是高中水平)。

2.定義\(i=\sqrt\)

3.引入複數(即形如\(a+bi\)(a,b均為實數)的數的集合)

4.\((cos\theta+i\times sin\theta)^k=cos(k\theta)+i\times sin(k\theta)\)

5.顯然我們對多項式fft之後得到的答案不是我們想要的,那麼這時候就需要反著用fft把式子再變回去(本文記做ifft)。

這裡證明一下第四條,用歸納法。

顯然當\(k=1\)時成立。

當\(k\)成立時,我們有:

\((cos\theta+i\times sin\theta)^\)

\(=(cos\theta+i\times sin\theta)^k\times (cos\theta+i\times sin\theta)\)

\(=(cos(k\theta)+i\times sin(k\theta))\times (cos\theta+i\times sin\theta)\)

\(=cos(k\theta)cos\theta+i\times sin(k\theta)cos\theta+i\times cos(k\theta)sin\theta+i^2\times sin(k\theta) sin\theta\)

\(=cos(k\theta)cos\theta-sin(k\theta) sin\theta+i\times (sin(k\theta)cos\theta+cos(k\theta)sin\theta)\)

\(=cos((k+1)\theta)+i\times sin((k+1)\theta)\)

得證。

設\(a(x)=\sum_^a_ix^i,b(x)=\sum_^b_ix^i\),求\(a(x)\times b(x)\)後的多項式係數。

顯然我們有乙個\(o(n^2)\)的解法,但是實在是太慢了。

考慮到乙個\(n-1\)次多項式可以看做是定義在複數域上的函式,則我們一定可以找到n個點來唯一確定這個函式。

當然我們也可以通過這些點來表示這個多項式。

假設:\(a(x)\)被表示為:\(<(x_0,y_),(x_1,y_),\ldots,(x_,y_})>\)

\(b(x)\)被表示為:\(<(x_0,y_),(x_1,y_),\ldots,(x_,y_})>\)

顯然\(a(x)\times b(x)\)被表示為:\(<(x_0,y_y_),(x_1,y_y_),\ldots,(x_,y_}y_})>\)

這裡多取了點的原因在於\(a(x)\times b(x)\)是乙個\(2n-2\)次多項式,則至少要取\(2n-1\)個點才能保證正確。

但是顯然還是\(o(n^2)\)的。

考慮設\(a(x_i)=a_0(x_i^2)+x_ia_1(x_i^2)\),其中:

\(a_0(x)=a_0+a_2x+a_4x^2+\ldots+a_x^+1}\)

\(a_1(x)=a_1+a_3x+a_5x^2+\ldots+a_x^+1}\)

其實就是按照係數下標的奇偶性分類了一下。

此時我們再令取點的\(x\)值為\(\)

我們發現把\(x\)平方後我們的取值瞬間縮小了一半,而原式唯一變化的就是\(a_1(x)\)前的符號。

看起來我們似乎找到了\(o(nlogn)\)的可行方案。

但是很可惜,這樣優秀的\(x\)取值的性質只會保留一次,也就是說我們只是得到了乙個\(o(\frac)\)。

如何才能每次將問題的規模縮小一半是我們的目標。

有個人告訴你:不如試試\(x_n=cos\frac+i\times sin\frac\) 的 \(0\ldots n-1\)次方作為\(x\)的取值。

這塊大家一直有個疑惑:這是怎麼構造出來的啊?

事實上傅利葉變換最早是應用於訊號處理上的,傅利葉提出:任何連續週期訊號可以由一組適當的正弦曲線組合而成。

多項式可以看做非連續週期訊號,然後通過各種奇妙的姿勢讓它逼近正弦曲線的組合形,詳情可以看鬆鬆松wc2018的課件。

「逼近」顯然用到了微積分,不適合初學者,所以就直接跳過了。(其實我也不會……)

(再多說一點吧,其實上面和下面的數學推理完全可以從物理層面理解,還是可以參考鬆鬆松wc2018的課件)

那麼令取點的\(x\)值為\(\)

我們可知:

\((x_n^)^2\)

\(=x_n^\)

\(=cos\frac+i\times sin\frac\)

\(=cos\frac}+i\times sin\frac}\)

\(=x_}^k\)

\(x_n^\)

\(=cos\frac+i\times sin\frac\)

根據三角函式的週期性可知,\(k\)對\(n\)取模顯然不會對答案造成影響。

於是我們有\(x_n^=x_n^\)

那麼顯然對於\(<(x_n^0)^2,(x_n^1)^2,\ldots,(x_n^)^2>\)

它等效於\(\)

我們好像看到了\(o(nlogn)\)的曙光了。

顯然我們可以對\(x\)的取值折半,然後對於左右區間的\(x\)值遞迴下去即可。

q1:誒等等,「再試」裡面的內容好像沒有應用上啊……

a1:那就轉化一下,其實我們只需要求乙個區間的\(a_0(x)\)和\(a_1(x)\)值遞迴下去求\(a(x)\)即可。

也就是說其實我們是得到了:

\(<(a_0)_0,(a_0)_1,\ldots,(a_0)_-1},(a_1)_0,(a_1)_1,\ldots,(a_1)_-1}>\)

q2:這好像是畫蛇添足……

a2:emmm……我說這個可以用於常數優化你信嗎……

顯然\(a(x_n^k)=(a_0)_}+x_n^k(a_1)_}\)

取模是因為,不要忘了我們的取值是由兩個一樣的左右區間合併在一起的。

那麼我們得到了\(\)

(其中\(a_k=a(x_n^k)\))

我們好像把這個序列的長度減少了一半誒!那自然是快了二倍啊。

不要忘了n要滿足始終是2的倍數,所以n要取2的整數次冪,同時將沒用的次冪的係數填成0。

q3:ifft怎麼做啊?

a3:繼續看下去……?

略講一下ifft。

顯然我們可以把fft的最初演算法(也就是dft)看做兩個矩陣相乘。

兩個矩陣分別乙個填\((x_n^k)^m\),乙個填係數,可以上參考處原部落格看矩陣。

那麼我們把第乙個矩陣變成逆矩陣豈不是為ifft?

其實就是這樣,並且事實上就是填\(((x_n^)^m)/n\),具體證明過程看參考處原部落格。

剩下的做法就和fft一樣啦。

事實上我上述講的內容其實沒有多少用(滑稽。

因為你理解半天也不如不理解知道怎麼用然後默寫下來。

但是理解了更好背啊。

模板:hdu1402:a * b problem plus:

應用:bzoj3527:[zjoi2014]力:

+++++++++++++++++++++++++++++++++++++++++++

快速傅利葉變換FFT

fft的作用就不多說了,搞訊號處理的人都會用上。fft的由來 傅利葉變換ft 離散傅利葉變換dft 快速傅利葉變換fft。學習資料 1 陳後金的 數字訊號處理 裡面深入淺出,該有的公式都有,程式設計思想也有。2 一篇系統講述傅利葉變換的帖子 3 學生對fft的理解 4 工程人員對fft的簡單明瞭的總...

快速傅利葉變換 FFT

bzoj 2179 fft快速傅利葉 果題 bzoj2194 請計算c k sigma a i b i k 其中 k i n 並且有 n 10 5。a,b中的元素均為小於等於100的非負整數。注意到i 和 i k有奇妙的聯絡 不妨嘗試把b翻轉 然後就變成卷積了。貼個模板 include define...

快速傅利葉變換 FFT

首先說一下我用fft做什麼,我要做的是多項式乘法,或者說,加速多項式乘法。考慮多項式a x j 0n 1aj xj,它一共有 n 項,我們稱它的次數界為 n。假設我們有兩個次數界為 n 的多項式a x 和b x 要求它們的和是非常簡單的,只需要將對應的係數相加,複雜度為o n 如果要求他們的積,則需...