快速傅里叶变换与快速数论变换(一)

转载请注明

 

目录

转载请注明

1.前言

2.前提知识

2.1秦九韶算法

2.1.1介绍

2.1.2算法的具体过程

2.1.3 CODE

2.2复数

2.2.1虚数

2.2.2复数及其属性

2.2.3复数的运算法则

2.2.4一种特殊的复数

2.2.5欧拉公式

2.3多项式的两种表示方式

2.3.1系数向量法

2.3.2点值法

2.3.3两者之间的联系

2.4单位根

2.4.1基本概念

2.4.2性质

3.FFT的计算过程概要

4.DFT(离散傅里叶变换)

4.1单位复数根的点值法表示多项式

4.2 DFT()

4.3 DFT的两种求法

4.3.1递归分治法(自顶向下,常数比较大)

4.3.2迭代法(自底向上,常数比较小)

5. IDFT(逆离散傅里叶变换)

5.1 IDFT与逆矩阵 

5.2 伪代码

6.卷积定理

7.快速数论变换

7.1原根

7.2 常用模数和对应原根的表

8.参考文献


1.前言

我计划将分成两章讲解“快速傅里叶变换与快速数论变换”。这一篇博客是我在研究和学习了3~4天的FFT和FNT的基础之上诞生的。

本片博客主要讲解FFT和FNT的最基本的知识。

FFT和FNT是用来解决数个多项式相乘的问题的。

 

2.前提知识

2.1秦九韶算法

2.1.1介绍

秦九韶算法(在西方叫做“霍纳法则”)能在 O(n) 的时间内计算 n 次多项式的值

该多项式可以表示为:a_0+a_1 x+a_2x^2+...+a_{n-1}x^{n-1}

2.1.2算法的具体过程

a_0+a_1 x+a_2x^2+...+a_{n-1}x^{n-1}

\Rightarrow a_0+(a_1+a_2x+...+a_{n-1}x^{n-2})x

\Rightarrow a_0+(a_1+(a_2+..+a_{n-1}x^{n-3})x)x

...

\Rightarrow a_0+(a_1+(a_2+(..a_{n-1}x..)x)x)x

2.1.3 CODE

double f (int n,double a[],double x){//n代表a[]的大小,数组的传递需要指定数组大小
    int i;                           //a[]储存每个x项的系数值,在函数外初始化
    double p=a[n];//初始化p;
    for(i=n;i>0;i--)
        p=a[i-1]+x*p;
    return p;
}

 

2.2复数

2.2.1虚数

 x^2=-1

则 x=\pm \sqrt {-1},此方程在实数集上没有解。于是,我们再设置一个复数集。

在复数集上,我们设 i^2=-1,于是此方程也有解。其中,我们把 i 叫做虚数

2.2.2复数及其属性

我们把实数+虚数结合体叫做复数,比如:1+2i 

其中,1 是实部,2i 是虚部。

设复数 Z=a+bi,则 Z 的模长为 \left | Z \right |=\sqrt{a^2+b^2} ,辐角为 \theta = arctan \frac{b}{a}

2.2.3复数的运算法则

设 Z_1=a+biZ_2=c+di

则 Z_1 \cdot Z_2= (ac-bd)+(ad+bc)i

则模长为 \sqrt{(a^2+b^2)(c^2+d^2)},辐角为 \theta=arctan \frac{ad+bc}{ac-bd}=\theta_1+\theta_2

因此,有结论:两个复数相乘:模长相乘,辐角相加

2.2.4一种特殊的复数

一种特殊的复数:e^{i\varphi }=cos \varphi +i \cdot sin \varphi, 它的模长是 \sqrt{cos \varphi ^2+sin \varphi^2 }=1, 辐角为 \theta= arctan \frac{b}{a}=\varphi

这个复数可以用来旋转一个复数.

比如,设 Z=a+bi,  再设 Z_1=Z \cdot e^{i\varphi}

由上面的结论,我们得到:\left | Z_1 \right |=\left | Z \right |=\sqrt{a^2+b^2},  \theta=arctan\frac{b}{a}+\varphi

即复数 Z 顺时针旋转了 \theta

2.2.5欧拉公式

令上面的 \varphi=\pi,得到 e^{i\pi}+1=0

这就是著名的欧拉公式。

 

2.3多项式的两种表示方式

设两个 n 次多项式分别为 A(x)= \sum_{i=0}^{n-1}a_ix^i ,B(x)= \sum_{i=0}^{n-1}b_ix^i

该多项式在数学上有两种表示方式,分别为:系数向量法、点值法

注意,在这里,我们用任意一个变量取代 x,也就是把上面这些式子当作形式幂级数(形式幂级数的概念在母函数中提到过) 

2.3.1系数向量法

所谓的系数向量法就是利用多项式中未知数前的系数构成的一组系数向量(我们将它看成是列向量)

即  (a_0,a_1,...a_{n-1}) 和 (b_0,b_1,...b_{n-1})

若采用系数向量法来表示两个多项式相乘,

则有 c_k=\sum_{i=0}^{k}a_ib_{k-i} (k \in [0,2n-2])

时间复杂度为 O(n^2)

2.3.2点值法

所谓的点值法就是用 n 个 点值对表示该多项式,每一个点值对由 x 和 a(x) 构成

即 \{(x_0,a(x_0)),(x_1,a(x_1)),...(x_{n-1},a(x_{n-1})) \}

点值法的本质就是取 n 个样本,从而构成一个 n 阶方阵。然后就可以唯一确定一组系数向量,从而唯一确定一个多项式

2.3.3两者之间的联系

系数法 \rightarrow 点值法     “求值”运算

点值法 \rightarrow 系数法     “插值”运算

 

2.4单位根

2.4.1基本概念

设 \omega 为一个复数,令 \omega ^n=1,我们称其为 n 次单位复数根(就是模长为 1 的复数的 n 次等于 1 的复数集)

2.4.2性质

有以下性质:

性质一:复数集的基数是 n,也就是有 n 个这样的复数

性质二:复数集中的复数均匀分布在复平面上的单位圆上,将单位圆均匀的分成了 n 个部分

性质三:复数集中的各个复数的模长为 1

性质四:复数集中的元素的形式为 \omega =e^{\frac{2\pi ki}{n}} ,其中  k \in[0,n-1]。我们把 \omega_n=e^{\frac{2\pi i}{n}} 叫做主 n 次单位复数根

性质五:由性质四,得到复数集中各元素分别为:\omega_{n}^{0},\omega_{n}^{1},..\omega_{n}^{n-1}

性质五:复数集是一个群,满足以下恒等式

             一、\omega_{n}^{j} \cdot \omega_{n}^{k}=\omega_{n}^{j+k(mod \ n)} 

             二、\omega_{dn}^{dk} = \omega_{n}^{k}(消去引理)

             三、(由恒等式二得到本推论)\omega_{n}^{n/2}=\omega_{2}^{1}=-1

             四、\omega_{n}^{0} = \omega_{n}^{n}=1

             五、\sum_{i=0}^{n-1}(\omega_{n}^{i})^p=0,其中,p 是一个常数

             六、\omega_{n}^{n/2+k}=\omega_{n}^{n/2}\cdot \omega_{n}^{k}=\omega_2\cdot\omega_{n}^{k}=-\omega_{n}^{k} (折半引理)

备注:折半引理是FFT得以成立的充要条件

 

3.FFT的计算过程概要

polynomial-multiplication

(图片摘自图片原文地址

 

STEP 1:将系数向量A,B转换为点值法  ------------------O(nlogn)

STEP 2:将A,B两个点值相乘 ---------------------------------O(n)

STEP 3:将乘好以后的点值转换为新的系数向量C------O(nlogn)

因此,可以得到 FFT 的时间复杂度为 O(nlogn)

 

我们将STEP 1 叫做 DFT(即离散傅里叶变换),将STEP 2 叫做 IDFT(即逆离散傅里叶变换)

STEP 1 和 STEP 2互为逆运算

 

接下来,我将分成了两个部分(DFT和IDFT)来讲解FFT是怎么算的

不过,在此之前,约定下文中的 n 是 2 的幂次(即 n=2^m,不到 2^m,就用 0 补齐)

 

4.DFT(离散傅里叶变换)

DFT 是将系数向量转化为点值,是求值运算

设多项式为 A(x)= \sum_{i=0}^{n-1}a_ix^i

设多项式的系数向量 (a_0,a_1,...a_{n-1}) 为  \underset{a}{\rightarrow}  (已知)

设用点值法表示为 \{(x_0,a(x_0)),(x_1,a(x_1)),...(x_{n-1},a(x_{n-1})) \}

 

4.1单位复数根的点值法表示多项式

接下来,用 n 次单位复数根中的 n 个复数和其对应的多项式的值,分别代替点值法中的 x_i 和 A(x_i)

从而得到一组新的点值式:\{(\omega_{n}^{0},A(\omega_{n}^{0}) ),(\omega_{n}^{1},A(\omega_{n}^{1})),...(\omega_{n}^{n-1},A(\omega_{n}^{n-1})) \},记作 \underset{y}{\rightarrow}(未知)

则通过 DFT_n 运算:\underset{y}{\rightarrow}DFT_n \underset{a}{\rightarrow}, 得到 \underset{a}{\rightarrow} 的离散傅里叶变换值 \underset{y}{\rightarrow}

 

4.2 DFT(DFT_n

设 A(\omega _{n}^{k})=\sum_{i=0}^{n-1}a_{i}(\omega_{n}^{k})^i

再设 A_1(\omega _{n}^{k})=\sum_{i=0}^{n-1}a_{2i}(\omega_{n}^{k})^i,  A_2(\omega _{n}^{k})=\sum_{i=0}^{n-1}a_{2i+1}(\omega_{n}^{k})^i

 

那么就有 A(\omega_{n}^{k})=A_1(\omega_{n}^{2k})+A_2(\omega_{n}^{2k})

由 2.4.2 的消去引理得到:A(\omega_{n}^{k})=A_1(\omega_{n/2}^{k})+A_2(\omega_{n/2}^{k})\cdot \omega_{n}^{k} ------------------------(1)

由 2.4.2 的折半引理得到:A(\omega_{n}^{k+n/2})=A_1(\omega_{n/2}^{k})-A_2(\omega_{n/2}^{k})\cdot \omega_{n}^{k}-----------------(2)

 

观察 (1) 和 (2),我们得到一个结论:每次计算一个 A(\omega_{n}^{k}) 之后,就能直接计算得到 A(\omega_{n}^{k+n/2})

根据这个结论,就能使得原问题的规模缩小到原来的一半,因此,DFT 的时间复杂度就是 O(nlogn) 

讲的通俗一点就是:

A(\omega_{n}^{0})=A(\omega_{n}^{n/2})

A(\omega_{n}^{1})=A(\omega_{n}^{n/2+1})

...

A(\omega_{n}^{n/2-1})=A(\omega_{n}^{n-1})

 

4.3 DFT的两种求法

4.3.1递归分治法(自顶向下,常数比较大)

以下是伪代码:

DFT(\underset{a}{\rightarrow}):

            n= \underset{a}{\rightarrow}.length

            if(n==1) \ return \underset{a}{\rightarrow}

            \omega=1

            \omega_n=e^{\frac{2\pi i}{n}}

            y_{[0]}=DFT(a_0,a_2,a_4...)

            y_{[1]}=DFT(a_1,a_3,a_5...)

            for \ k=0 \ to \ n/2-1 :

                   y_k=y_{k}^{[0]}+y_{k}^{[1]}\cdot \omega

                   y_k=y_{k}^{[0]}-y_{k}^{[1]}\cdot \omega

                   \omega=\omega \cdot \omega_n

            return \ y 

 

4.3.2迭代法(自底向上,常数比较小)

以 n=16 为例子,观察下图中系数向量在分治法中的变化:

 

bit-reverse

 (图片摘自图片原文地址

 

STEP 1 : 是全序排列

STEP 2 : 末位为0的在左树,末位为1的在右树

STEP 3 : 倒数第二位为0的在左树,倒数第二位为1的在右树

STEP 4 : 倒数第三位为0的在左树,倒数第三位为1的在右树

 

考虑用迭代的方法计算 DFT,那么只要知道 STEP  log_2 n 的系数向量的顺序就可以自底向上迭代得到 \underset{y}{\rightarrow}

再观察 STEP 4 中个系数的顺序,我们发现:

0841221061419513311715
0000100001001100001010100110111000011001010111010011101101111111
0000000100100011010001010110011110001001101010111100110111101111
0123456789101112131415

将 STEP 4 中个系数的二进制翻转后的数是逐一递增的。(我们把这个叫做逆序置换

 

我们假设 rev(i) 是 将 i 的二进制翻转之后的数,那么我们就可以得到以下的伪代码:

reverse(\underset{a}{\rightarrow}:

             for \ i =0 \ to  \underset{a}{\rightarrow}.length :

                    a(i) = rev(i)

             return \underset{a}{\rightarrow}

 

DFT(\underset{a}{\rightarrow}:

           \underset{A}{\rightarrow} = reverse(\underset{a}{\rightarrow})

            n= \underset{A}{\rightarrow}.length 

            for \ s=1 \ to \ log_2n:

                   m=2^s

                   \omega_{n}=e^{\frac{2\pi i}{m}}

                   for \ j=0 \ to \ n-1\ by \ m:

                          \omega=1

                         for \ k=0 \ to \ m/2-1: 

                                t=\omega \cdot A[j+k+m/2]

                                u=A[j+k]

                                A[j+k]=u+t

                                A[j+k+m/2]=u-t

                                \omega=\omega \cdot \omega_n

            return \underset{A}{\rightarrow}

  reverse (逆序置换)的具体代码:

//采用DP
int rev[N];
void reverse(int n)
{
    memset(rev,0,sizeof(rev));
    for(int i=0;i<n;++i)
        rev[i]=(rev[i/2]>>1)|((i&1)<<(n-1));//(i&1)表示当前的项的奇偶,rev[i]的右n-1位与rev[i/2]的右n-1位相同
}

 

 

5. IDFT(逆离散傅里叶变换)

IDFT 是将点值转化为系数向量,是插值运算

设多项式为 A(x)= \sum_{i=0}^{n-1}a_ix^i

设多项式的系数向量 (a_0,a_1,...a_{n-1}) 为  \underset{a}{\rightarrow}  (未知) 

通过 DFT 得到一组点值 \{ (\omega_{n}^{0},A(\omega_{n}^{0})),(\omega_{n}^{1},A(\omega_{n}^{1}))...(\omega_{n}^{n-1},A(\omega_{n}^{n-1})) \}  ,记作\underset{y}{\rightarrow} (已知)

 

则有 \underset{a}{\rightarrow}IDFT  \underset{y}{\rightarrow}-----------(*)

 

5.1 IDFT与逆矩阵 

  计算 (*) ,本质上就是解下列方程组:

  写成矩阵的形式就是:

   

    

      (以上图片截自图片原文地址

        这样,IDFT 就相当于把 DFT 过程中的 \omega_{n}^{i} 换成 \omega_{n}^{-i},然后做一次 DFT,之后结果除以 n 就可以了。

       

5.2 伪代码

把上面两种 DFT伪代码中的 \underset{a}{\rightarrow} 换成 \underset{y}{\rightarrow}\underset{y}{\rightarrow} 换成 \underset{a}{\rightarrow}即可。最后,每一项元素除以 n

 

6.卷积定理

设  a,b 是两个 n 次( n 是 2 的幂次,不到 n 就用 0 补齐)多项式,那么有:

a \bigotimes b=IDFT_{2n}(DFT_{2n}(a) \cdot DFT_{2n}(b))(  \bigotimes 表示卷积)

 

注意:这里不是 n ,而是 2n !因为 a,b 这两个 n 次多项式相乘的话,就会多产生 n-1 项

比如:

a=1+2x+3x^2-------------------------------------------------(1)

b=1+2x+3x^2--------------------------------------------------(2)

那么 a \bigotimes b=1 + 4 x + 10 x^2 + 12 x^3 + 9 x^4-------(3)

观察得到,(3) 比 (1) 或 (2) 多了 2 项,所以要把原来的 n 扩展为 2n

 

7.快速数论变换

我们发现,使用 n 次单位复数根可以简化多项式的计算,但是复数的计算难免会产生精度的误差。在对大整数的多项式的计算过程中就会失去优势,因此,我们将采用一种新的方式来代替了原来的 n 次单位复数根。

7.1原根

设一个素数为 p,根据费马大定理有:a^{p-1}\equiv 1 \ mod \ p  \Leftrightarrow \omega_{n}^{n} = 1

若某个数 g 是 p 的原根,则有 \forall \ 1\leq x < y \leq p-1 , \ g^x \neq g^y \ mod \ p  

 

根据原根的特点,我们设一个素数 p=a \cdot 2^b+1,

设  g_n=g^{\frac{p-1}{n}}  \Leftrightarrow \omega_n=e^{\frac{2 \pi i}{n}}(对应主 n 次单位复数根)

有  g_{n}^{n} = g^{(\frac{p-1}{n})\cdot n}=1 \ mod \ p \Leftrightarrow \omega_{n}^{n}=1(对应 n 次单位复数根性质一)

有 g_{n}^{0},g_{n}^{0},..g_{n}^{n-1} 互不相同 \Leftrightarrow \omega_{n}^{0},\omega_{n}^{1},...\omega_{n}^{n-1} 互不相同(对应 n 次单位复数根性质二)

有 g_{n}^{n/2}=\sqrt{g_{n}^{n}}, 于是 g_{n}^{n/2}=\pm 1 ,

又因为g_{n}^{0}=1g_{n}^{0}\neq g_{n}^{n/2} \ mod \ p,所以  g_{n}^{n/2}=-1 \Leftrightarrow \omega_{n}^{n/2}=-1(对应 n 次单位复数根性质三)

 

有了上面三条 一 一对应的性质,我们就可以使用这样的 p 对应的 g_n 代替  n 次单位复数根。

 

7.2 常用模数和对应原根的表

r⋅2k+1rkg
3112
5122
17143
97355
193365
257183
768115917
1228931211
409615133
655371163
78643331810
576716911193
73400337203
2306867311213
10485760125223
1677721615253
4697620497263
998244353119233
1004535809479213
2013265921152731
228170137717273
32212254733305
7516192768135313
773094113299337
20615843020933622
206158430208115377
27487790694415393
65970697666573415
395824185999379425
791648371998739435
26388279066624115447
123145302310912135453
133700613937561719463
379991218559385727475
4222124650659841154819
78812993478983697506
315251973915934737523
1801439850948198415556
194555503902405427327565
417934045419982028929573

    (图片摘自图片原文地址

 

8.参考文献

1.http://blog.miskcoo.com/2015/04/polynomial-multiplication-and-fast-fourier-transform#i-12

2.http://blog.miskcoo.com/2014/07/fft-prime-table

3.https://www.cnblogs.com/rvalue/p/10120174.html#fft%E7%9A%84%E9%80%9F%E5%BA%A6%E4%BC%98%E5%8C%96%E4%B8%8E%E8%BF%AD%E4%BB%A3%E5%AE%9E%E7%8E%B0

4.算法导论

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值