利用快速傅里葉計算多項式相乘

FFT多項式計算

傅里葉變換是一個很大的概念,裏面包含太多太多東西,整篇在傅里葉變換中只是一個小應用而已。就我的理解,描述快速傅里葉變換優化多項式乘法的原理和具體實踐。

傅里葉變換

傅里葉變換是一種線性積分變換,用於信號在時域(或空域)和頻域之間的變換。

一般情況下,若傅里葉變換一詞不加任何限定語,則指的是連續傅里葉變換。(連續)傅里葉變換定義如下:傅里葉變換將可積函數f:RCf: \mathbb{R} \rightarrow \mathbb{C}表示成復指數函數的積分或級數性質。
f^(ξ)=f(x)e2πixξdx \hat{f} \left( \xi \right) = \int_{-\infty}^{\infty} f \left( x \right) e^{-2\pi i x \xi } dx
其中ξ\xi爲任意實數。自變量xx表示時間,變換變量ξ\xi表示頻率。在多數情況下,傅里葉變換是可逆的,即可以通過f^\hat{f}得到其原函數ff,定義如下:
f(ξ)=f^(ξ)e2πiξxdξ f \left( \xi \right) = \int_{-\infty}^{\infty} \hat{f} \left( \xi \right) e^{2\pi i \xi x} d \xi

離散傅里葉變換

爲了在科學計算和數字信號處理等領域使用計算機進行傅里葉變換,必須將函數xnx_{n}定義在離散點而非連續域內,且須滿足有限性和週期性等提交。這種情況下,使用離散傅里葉變換(Discrete Fourier Transform,DFT),DFT是傅里葉變換在時域和頻域上都呈離散的形式,函數定義如下:
x^n=k=0N1xkei2πNknn=0,,N1 \hat{x}_{n} = \sum_{k=0}^{N-1}x_{k} e^{-i \frac{2\pi}{N} k n} \qquad n = 0, \cdots, N-1
其逆變換爲:
xk=1Nn=0N1x^nei2πNnkk=0,,N1 x_{k} =\frac{1}{N} \sum_{n=0}^{N-1} \hat{x}_{n} e^{-i \frac{2\pi}{N} n k} \qquad k = 0, \cdots, N-1

單位根

數學上,nn次單位根是nn次冪爲1的負數。定義爲ωn=1(n=1,2,3,)\omega^{n}=1 \quad \left( n=1,2,3,\cdots\right)ω\omegann次單位根。單位的nn次根有nn個:e2πki/n(k=0,1,2,,n1)e^{2\pi k i / n} \quad \left(k=0,1,2,\cdots, n-1 \right)。我們用ωn0,ωn1,,ωnn1\omega_{n}^{0}, \omega_{n}^{1}, \cdots, \omega_{n}^{n-1}表示這個nnnn次根,ωni=e2πki/n\omega_{n}^{i} = e^{2\pi k i / n}

結合歐拉公式,可以很容易得看出,ωnk=e2πkni=cos(2πkn)+isin(2πkn)=1\omega_{n}^{k} = e ^{2\pi \frac{k}{n} i } = cos\left(2\pi \frac{k}{n}\right) + i \cdot sin \left( 2\pi \frac{k}{n} \right) = 1

對於n0,k0,d0n \geq 0, k \geq 0, d \geq 0,有ωdndk=(e2πi/dn)dk=(e2πi/n)k=ωnk\omega_{dn}^{dk}=\left( e^{2\pi i /dn}\right)^{dk} = \left( e^{2\pi i /n}\right)^{k} = \omega_{n}^{k}

對於n\forall n滿足n>0n > 02n2 | n,有ωnk+n2=e2πin(k+n2)=e2πik/neπi=ωnk(cosπ+isinπ)=ωnk\omega_{n}^{k + \frac{n}{2}} = e ^ {\frac{2 \pi i}{n} \left( k + \frac{n}{2}\right)} = e^{2 \pi i k / n} e^{\pi i} = \omega_{n}^{k} \left( cos \pi + i sin \pi \right) = -\omega_{n}^{k}

多項式

形如a0+a1x++anxna_{0} + a_{1} x + \cdots + a_{n} x^{n}的多項式被稱爲多項式,記爲A(x)=i=0n1aixiA\left( x \right) = \sum_{i=0}^{n-1} a_{i} x^{i},其中ai,i=0,1,,na_{i}, i=0,1,\cdots,n爲係數,用係數表示多項式爲a=(a0,a1,,an)\vec{a}=\left(a_{0}, a_{1}, \cdots, a_{n} \right)a\vec{a}就爲多項式的係數表示法

我們知道通過n+1n+1個不同的點{(x0,y0),,(xn,yn)}\left\{\left(x_{0},y_{0}\right),\cdots, \left(x_{n},y_{n}\right) \right\}就可以唯一確定一個nn次多項式,{(x0,y0),,(xn,yn)}\left\{\left(x_{0},y_{0}\right),\cdots, \left(x_{n},y_{n}\right) \right\}爲多項式的點值表示法

快速傅里葉變換

快速傅里葉變換(Fast Fourier Transform,FFT),是計算離散傅里葉變換及其逆變換的快算算法。按照DFT的定義,計算一個長爲nn的序列需要的時間複雜度爲O(n2)O\left( n^{2} \right),而FFT通過把DFT矩陣分解爲稀疏因子之積來快速計算變換,從而將時間複雜度降到O(nlogn)O\left( nlog n \right)

庫裏-圖基快速傅里葉變換算法是最常見的FFT算法,基於分治策略,可將時間複雜度降爲O(nlogn)O\left( nlog n \right)

假設一個多項式表示爲A(x)=i=0n1aixiA\left( x \right) = \sum_{i=0}^{n-1} a_{i} x^{i},用係數表示法表示就是向量a=(a0,a1,,an)\vec{a}=\left(a_{0}, a_{1}, \cdots, a_{n} \right)。用點值表示,將nnnn次單位根ωn0,ωn1,,ωnn1\omega_{n}^{0}, \omega_{n}^{1}, \cdots, \omega_{n}^{n-1}帶入到多項式爲A(ωnk)=i=0n1aiωnki,k=0,1,,n1A\left( \omega_{n}^{k} \right) = \sum_{i=0}^{n-1} a_{i} \omega_{n}^{ki}, k = 0,1,\cdots, n-1。現在我們和DFT定義的公式比對,A(ωni)A\left(\omega_{n}^{i}\right)就是是aia_{i}的DFT,那麼aia_{i}就是A(ωni)A\left(\omega_{n}^{i}\right)就是的IDFT。記爲A(ωni)=DFT(ai)A\left(\omega_{n}^{i}\right) = DFT\left( a_{i} \right)

下面我們就依據上面陳列的基礎基礎,對A(ωnk)A\left(\omega_{n}^{k}\right)進行公式推導:
A(ωnk)=i=0n1aiωnki=i=0n21a2iωn2ki+ωnki=0n21a2i+1ωn2ki=i=0n21a2iωn2ki+ωnki=0n21a2i+1ωn2ki       \begin{matrix} A\left(\omega_{n}^{k}\right) &= \sum_{i=0}^{n-1} a_{i}\omega_{n}^{ki} \qquad \qquad \qquad \qquad \qquad \\ \\ & = \sum_{i=0}^{\frac{n}{2}-1} a_{2i}\omega_{n}^{2ki} + \omega_{n}^{k} \sum_{i=0}^{\frac{n}{2}-1} a_{2i+1}\omega_{n}^{2ki} \\ \\ & = \sum_{i=0}^{\frac{n}{2}-1} a_{2i}\omega_{\frac{n}{2}}^{ki} + \omega_{n}^{k} \sum_{i=0}^{\frac{n}{2}-1} a_{2i+1}\omega_{\frac{n}{2}}^{ki} \; \; \; \end{matrix}
又由於
A(ωnk+n2)=i=0n1aiωn(k+n2)i=i=0n21a2iωn2ki+ωnk+n2i=0n21a2i+1ωn2ki=i=0n21a2iωn2kiωnki=0n21a2i+1ωn2ki \begin{matrix} A\left(\omega_{n}^{k + \frac{n}{2}}\right) &= \sum_{i=0}^{n-1} a_{i}\omega_{n}^{\left(k+ \frac{n}{2}\right)i}\qquad \qquad \qquad \qquad \quad \\ \\ & = \sum_{i=0}^{\frac{n}{2}-1} a_{2i}\omega_{n}^{2ki} + \omega_{n}^{k + \frac{n}{2}} \sum_{i=0}^{\frac{n}{2}-1} a_{2i+1}\omega_{n}^{2ki} \\ \\ & = \sum_{i=0}^{\frac{n}{2}-1} a_{2i}\omega_{\frac{n}{2}}^{ki} - \omega_{n}^{k} \sum_{i=0}^{\frac{n}{2}-1} a_{2i+1}\omega_{\frac{n}{2}}^{ki} \qquad \end{matrix}
可以看出,對於k<n2k < \frac{n}{2}時,只要代入ωn2,ωn22,,ωn2n21\omega_{\frac{n}{2}}, \omega_{\frac{n}{2}}^{2}, \cdots, \omega_{\frac{n}{2}}^{\frac{n}{2} - 1},就可以求出A(ωnk)A\left(\omega_{n}^{k}\right)A(ωnk+n2)A\left(\omega_{n}^{k + \frac{n}{2}}\right)
A(ωnk)=A1(ωn2k)+A2(ωn2k)A(ωnk+n2)=A1(ωn2k)A2(ωn2k)(1) \begin{matrix} A\left(\omega_{n}^{k}\right) \quad =& A_{1}\left(\omega_{\frac{n}{2}}^{k}\right) + A_{2}\left(\omega_{\frac{n}{2}}^{k}\right) \\ \\ A\left(\omega_{n}^{k + \frac{n}{2}}\right) = & A_{1}\left(\omega_{\frac{n}{2}}^{k}\right) - A_{2}\left(\omega_{\frac{n}{2}}^{k}\right) \end{matrix} (公式1)
不遞歸的僞代碼如下所示:

void get_rev(int bit)
{
    for(int i=0; i<(1<<bit); i++)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
/**
n爲2的冪次方
op==1,DFT
op==-1,IDFT
*/
void fft(cd *a,int n,int op)
{
    for(int i=0; i<n; i++)
    {
        if(i<rev[i])
        {
            cd tmp = a[i];
            a[i] = a[rev[i]];
            a[rev[i]] = tmp;
        }
    }
    for(int step=1; step<n; step<<=1)
    {
        cd wn=exp(cd(0,op*PI/step));
        for(int j=0; j<n; j+=step<<1)
        {
            cd wnk(1,0);
            for(int k=j; k<j+step; k++)
            {
                cd x=a[k];
                cd y=wnk*a[k+step];
                a[k]=x+y;
                a[k+step]=x-y;
                wnk*=wn;
            }
        }
    }
    if(op==-1)
    {
        for(int i=0; i<n; i++)
            a[i]/=n;
    }
}

費了好大經歷才把代碼和原理結合在一起,在網上搜了好久都沒有理解爲何代碼要這樣寫,後來在離散傅里葉變換和快速傅里葉變換課件中搜到一張圖,瞬間明白,其中的子操作被稱爲蝴蝶操作。如下圖所示,展示了一個8個點的DFT是怎樣分解成4個2個點的DFT。
在這裏插入圖片描述
蝴蝶操作見下圖,類似於蝴蝶形狀,是不是和上述公式1的計算相符合。
在這裏插入圖片描述

FFT實現多項式乘法

當現在有多項式A(x)A\left(x\right)和多項式B(x)B\left(x\right),令C(x)=A(x)B(x)C\left(x\right) = A\left(x\right) \cdot B\left(x\right),那麼如何求CC的係數cjc_{j}呢?

先引入一個定理,函數卷積的傅里葉變換是函數傅里葉變換的乘積。$C\left(x\right) 中次數爲j的項由A \left(x\right) 中次數爲k的項和B\left(x\right) 中次數j-k爲的項相乘得到。那麼我們先通過C\left(\omega_{n}\right) = A\left(\omega_{n}\right) B\left(\omega_{n},\right)IDFT,然後在通過IDFT計算c_{j}$。

    fft(a,n,1);
    fft(b,n,1);
    for(int i=0; i<s; i++) a[i]*=b[i];
    fft(a,n,-1);

備註

歐拉公式eix=cosx+isinxe^{ix} = cos x + i \cdot sin x

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章