FFTオン

高速フーリエ輸送(FFT)

・多項式

因子の発現

多項式界の数nに対して\(A(X)= \ sum_ {J = 0} ^ {N-1} {a_jx ^ J} \) 、発現ベクターの係数は係数で構成されている\ (A =(A_0、A_1、...、1-N-A_ {})\)

ポイント値式

多項式A(X)のセクタ番号nがポイント値の式の組のn個の点の値こと
\ [{(X_0、Y_0) 、(X_1、Y_1)、...、(X_ {N -1}、Y_ {N-1
})} \] ように、K = 0,1、...、N- 1は、 すべての\(X_Kの\)が変化し、
\ [Y_K = A(X_K)\ 】
単に、我々は任意にNの同じ数を代入し、その後ポイントを描くことができない時間の複雑さをポイント値計算を見つける(\ \シータ(2 ^ n))を\背後あなたは私たちが少し巧妙な値を使用している場合、あなたがして、最適化の時間の複雑さを作ることができ、見ることができます(\シータ(N- \ lg_2nを)\)\

(多項式の係数ポイント値決定フォームの発現から発現された)逆評価は、計算呼ば補間

・多項式演算

\ [C_j = \ sum_ {k = 0} ^ {J} {A_kB_ {JK}} \]

上記多項式乗算である、我々はAおよびBと呼ばれる、Cのコンボリューション(畳み込み)として表現(\ C = A \ Bのbigotimes)\

FFTの主なアイデアは、最初のポイントAに変換され、Bの値が表され、点Cを得られる発現値、及び、その後得係数C発現に対して再びそれを行います。

・DFTとFFT

遅いアプローチ以上、我々が使用する\(\シータ(N ^ 2 )\) 各多項式のためのポイント値に変わり、その後、使用する時間\(\シータ(N ^ 2 )\) バックの時間を回すために、明らかに非常に遅い、など暴力的ではありません。

私たちは、あなたがそれのいくつかのより多くを得ることができたら、各操作を行うことができるように、それは、いくつかの特別な番号を使用することが可能であると思いますか?答えはイエスです:単位根複雑な根

N -番目複合ルート満足\(\オメガ^ N = 1 \) 錯体(\ \オメガ\) ユニットkのn個の正確にn番目のルートコンプレックス、= 0,1、...、N- 1、 根である\(^ E {\ IK PI / N} \) この式を説明するために、我々は、複素指数形式が定義されている使用:
\ [^ {E} = COS IU(U)+ ISIN(U)\]

すなわち、均一としてN個のベクトルの上に分散単位円を、与えられます。
ここに画像を挿入説明

n番目の単位複素根の場合•

一例として、上図は、我々はすべてのn個(ここでは、8)サブユニット、複雑な根がベクトルですが、彼らは乗算感の下でグループを形成していることがわかります。

補助定理1: 補題消去)
\ [任意の整数n個の\ geqslant0ため、K \ geqslant0、およびd> 0、\]

\ [\オメガ^ {DK} _ {DK} = \オメガ^ {K} _ {N} \]

证明
\[ \omega^{dk}_{dk}=(e^{2\pi i/dn})^{dk}=(e^{2\pi i/n})^k=\omega^{k}_{n} \]
引理2:(折半引理)
\[ 如果n>0为偶数,那么n个n次单位根的平方集合就是n/2个n/2次单位根的集合 \]
证明
\[ (\omega^{k+n/2}_{n})^2=\omega^{2k+n}_n=\omega^{2k}_n\omega^n_n=(\omega^k_n)^2 \]
因此\(\omega^k_n\)\(\omega^{k+n/2}_n\)平方相等。

引理3:(求和引理)
\[ 对于任意整数n\geqslant0和不能被n整除的非负整数k,有 \]

\[ \sum_{j=0}^{n-1}(\omega^k_n)^j=0 \]

证明
\[ \sum_{j=0}^{n-1}(\omega^k_n)^j=\frac{(\omega^k_n)^0(1-(\omega^k_n)^n)}{1-\omega^{k}_{n}}=\frac{(\omega^n_n)^k-1}{\omega^{k}_{n}-1}=\frac{(1)^k-1}{\omega^{k}_{n}-1}=0 \]
因为要求k不能被n整除,而且仅当k被n整除时\[\omega^k_n=1\]成立,同时保证分母不为0。

DFT

回顾一下,我们希望计算次数界为n的多项式
\[ A(x)=\sum_{j=0}^{n-1}{a_jx^j} \]
\[\omega^0_n,\omega^1_n,...,\omega^{n-1}_n\]处的值。假设A以系数形式给出,接下来定义结果\(y_k\):
\[ y_k=A(\omega^k_n)=\sum_{j=0}^{n-1}a_j\omega^{kj}_n \]
向量\(y=(y_0,y_1,...,y_{n-1})\)就是系数向量\(a=(a_0,a_1,...,a_{n-1})\)离散傅里叶变换(DFT)。我们也记作\(y=DFT_n(a)\)

FFT

通过使用一种称为快速傅里叶变换(FFT)的方法,利用复根的特殊性质,我们就可以在\[\Theta(n\lg n)\]的时间内计算出\(DFT_n(a)\)

注意:通篇的n我们假设是2的整数次幂。

FFT利用分治策略,采用A(x)中偶数下标的系数与奇数下标的系数,分别定义两个新的次数界为n/2的多项式

\[ A^{[0]}(x)=a_0+a_2x+a_4x^2+...+a_{n-2}x^{n/2-1} \]

\[ A^{[1]}(x)=a_1+a_3x+a_5x^2+...+a_{n-1}x^{n/2-1} \]

可以很容易发现
\[ A(x)=A^{[0]}(x^2)+xA^{[1]}(x^2) \]
所以原问题转化为求两个次数界为n/2的多项式\[A^{[0]}(x)\]\[A^{[1]}(x)\]在点\[(\omega^0_n)^2,(\omega^1_n)^2,...,(\omega^{n-1}_n)^2\]的取值。

所以我们可以发现在求出\[A^{[0]}(x^2)\]\[A^{[1]}(x^2)\]以后,可以算出两个复根的结果:
\[ y_k=y^{[0]}_k+\omega^k_ny^{[1]}_k =A^{[0]}(\omega^{2k}_n)+\omega^k_nA^{[1]}(\omega^{2k}_n) =A(\omega^k_n) \]
还有
\[ y_{k+(n/2)}=y^{[0]}_k-\omega^{k}_ny^{[1]}_k =y^{[0]}_k+\omega^{k+(n/2)}_ny^{[1]}_k =A^{[0]}(\omega^{2k}_n)+\omega^{k+(n/2)}A^{[1]}(\omega^{2k}_n) \]
\[ =A^{[0]}(\omega^{2k+n}_n)+\omega^{k+(n/2)}A^{[1]}(\omega^{2k+n}_n) =A(\omega^{k+(n/2)}_n) \]

所以就有代码:

void FFT(comp *a,int n,int inv){
    if(n==1) return;
    int mid=n/2;
    for (int i=0;i<mid;++i) c[i]=a[i*2],c[i+mid]=a[i*2+1];
    for (int i=0;i<n;++i) a[i]=c[i];
    FFT(a,mid,inv);
    FFT(a+mid,mid,inv);
    comp wn={cos(2.0*pi/n),inv*sin(2.0*pi/n)},w={1,0};
    for (int i=0;i<mid;++i,w=w*wn){
        c[i]=a[i]+w*a[i+mid];
        c[i+mid]=a[i]-w*a[i+mid];
    } 
    for (int i=0;i<n;++i) a[i]=c[i];
}

·在单位复数根的插值

现在我们展示如何在单位复数根处插值来完成多项式乘法方案,使得我们把一个多项式从点值表达转换回系数表达。
我们可以把DFT写成矩阵乘积
\[ \left[ \begin{matrix} y_0\\ y_1\\ y_2\\ \vdots\\ y_{n-1} \end{matrix} \right]= \left[ \begin{matrix} 1 & 1 & 1 & 1 &\cdots& 1\\ 1 & \omega_n & \omega^2_n & \omega^3_n &\cdots& \omega^{n-1}_n\\ 1 & \omega^2_n & \omega^4_n & \omega^6_n &\cdots& \omega^{2(n-1)}_n\\ 1 & \omega^3_n & \omega^6_n & \omega^9_n &\cdots& \omega^{3(n-1)}_n\\ \vdots & \vdots& \vdots& \vdots& \ddots& \vdots\\ 1 & \omega^{n-1}_n & \omega^{2(n-1)}_n & \omega^{3(n-1)}_n &\cdots& \omega^{(n-1)(n-1)}_n \end{matrix} \right] \left[ \begin{matrix} a_0\\ a_1\\ a_2\\ \vdots\\ a_{n-1} \end{matrix} \right] \]
尴尬的是跑得贼慢:
ここに画像を挿入説明
随便卡卡就爆了....
分治难免递归,递归常数大。
于是,考虑改进。

・バタフライ変換

ここに画像を挿入説明
海賊一つは
見つけることができ、順にそれぞれは、配列中のそれらの最終位置に形成する下地バイナリ下にあります。
だから、プレーの反復的なスタイルがあるでしょう。

void FFT(Moon *a,int inv){
    int i,j,len;
    for (i=0;i<n;++i)
        if(i<R[i])swap(a[i],a[R[i]]);
    for (len=2;len<=n;len<<=1){
        int half=len/2;
        Moon w,wn={cos(Pi/half),inv*sin(Pi/half)};
        for (j=0;j<n-i;j+=len,w={1,0}){
            for (i=0;i<half;++i,w=w*wn){
                Moon q=w*a[j+half+i],Q=a[j+i];
                a[j+half+i]=Q-q;
                a[j+i]=Q+q;
            }
        }
    }
}
int main(){
    for (i=0;i<n;++i) R[i]=(R[i>>1]>>1)|((i&1)<<(p-1));
} 

ここに画像を挿入説明

おすすめ

転載: www.cnblogs.com/Chandery/p/11332777.html