学习笔记 - 快速傅里叶变换 / 大数A * B的另一种解法


前言

Fast Fast TLE

原本做大数乘法的时候是想偷懒的, 就百度了下大数 A * B 的代码, 无意中发现有使用FFT的做法, 于是便开始了学习 (受苦) , 本文用以记录算法应用层面上我对FFT的理解和一个手搓的大数乘法模版.

需要一定的复数知识, 但不多.

笔者对FFT的理解较为粗浅, 因此在下文可能大量略过某些部分的详细证明, 请见谅!

一、FFT是什么?

快速傅里叶变换( Fast Fourier Transform ), 是一种对离散傅里叶变换( Discrete Fourier Transform )的优化, 可令离散傅里叶变换的运算量大大降低, 在取样点数量较多的情况下可显著提升效率

二、FFT可以干什么?

1.多项式乘法

实际上, FFT可以大大提升卷积1的计算效率, 而当卷积的两个函数为多项式的时候, FFT则能在多项式乘法上大显神威.

2.大数乘法

关于乘法, 朴素的算法则是模拟我们自小学会的竖式乘法, 不难证明这样的算法的复杂度为O(n2), 然而这样的算法不仅容易精度溢出, 效率也不够高, 应用FFT则可以使算法的复杂度降低至O(nlogn).

观察一个数字, 如123456, 换种角度思考, 可以将其转化为以下的式子: 123456 = 1 ∗ 1 0 5 + 2 ∗ 1 0 4 + 3 ∗ 1 0 3 + 4 ∗ 1 0 2 + 5 ∗ 1 0 1 + 6 ∗ 1 0 0 123456 = 1 *10^5+2*10^4+3*10^3+4*10^2+5*10^1+6*10^0 123456=1105+2104+3103+4102+5101+6100再转化一次, 令x = 10, 则可以得到: 1 ∗ x 5 + 2 ∗ x 4 + 3 ∗ x 3 + 4 ∗ x 2 + 5 ∗ x 1 + 6 ∗ x 0 1 *x^5+2*x^4+3*x^3+4*x^2+5*x^1+6*x^0 1x5+2x4+3x3+4x2+5x1+6x0
从这个角度思考, 大数乘法不正是x = 10的情况下的多项式乘法吗?

三、FFT怎么做?

PS:强烈建议您通过这个视频进行学习并在需要的情况下结合下文理解, 个人认为这个视频讲得相当易懂

1. 系数表示法和点值表示法

任取一个n-1阶2 多项式, 将其表示为 a 0 + a 1 x + a 2 x 2 + . . . + a n − 1 x n − 1 a_0+a_1x+a_2x^2+...+a_{n-1}x^{n-1} a0+a1x+a2x2+...+an1xn1实际上我们已经得到了它的系数表示, 即 [ a 0 a 1 a 2 . . . a n − 1 ] \left[ \begin{array}{l} a_0&a_1&a_2&...&a_{n-1} \end{array} \right] [a0a1a2...an1]
那么什么是它的点值表示法呢?

对一个多项式 f ( x ) = a 0 + a 1 x + a 2 x 2 + . . . + a n − 1 x n − 1 f(x)= a_0+a_1x+a_2x^2+...+a_{n-1}x^{n-1} f(x)=a0+a1x+a2x2+...+an1xn1任取不小于n个xi带入并计算得到f(xi)即为其点值表示法:
{ ( x 0 , f ( x 0 ) , ( x 1 , f ( x 1 ) , … , ( x n − 1 , f ( x n − 1 ) } \left\{ (x_0,f(x_0),(x_1,f(x_1), \dots,(x_{n-1},f(x_{n-1}) \right\} { (x0,f(x0),(x1,f(x1),,(xn1,f(xn1)}

将其化为矩阵形式, 有
[ f ( x 1 ) f ( x 2 ) ⋮ f ( x − 1 ) ] = [ 1 x 0 x 0 2 … x 0 n − 1 1 x 1 x 1 2 … x 1 n − 1 … … … ⋮ … 1 x n − 1 x n − 1 2 … x n − 1 n − 1 ] [ a 0 a 1 ⋮ a n − 1 ] \left[ \begin{array}{l} f(x_1)\\ f(x_2)\\ \vdots \\ f(x-1) \end{array} \right] = \left[ \begin{array}{l} 1&x_0&x_0^2&\dots&x_{0}^{n-1}\\ 1&x_1&x_1^2&\dots&x_{1}^{n-1}\\ \dots&\dots&\dots&\vdots&\dots\\ 1&x_{n-1}&x_{n-1}^2&\dots&x_{n-1}^{n-1} \end{array} \right] \left[ \begin{array}{l} a_0\\ a_1\\ \vdots \\ a_{n-1} \end{array} \right] f(x1)f(x2)f(x1)=111x0x1xn1x02x12xn12x0n1x1n1xn1n1a0a1an1
PS:从 系数表示法 得到 点值表示法 的这一步即为DFT(离散傅里叶变换)

由范德蒙德行列式易证得当x0 ~ xn-1互不相同时矩阵可逆, 即当所取的xi不小于矩阵的阶加一时, 点值表示法和系数表示法一一对应.

h ( x ) = f ( x ) g ( x ) h(x)=f(x)g(x) h(x)=f(x)g(x)
在点值表示法的基础上, 要计算h(x)的表达式, 只需要取相同的xi得出f(xi)和g(xi)并相乘, 再从(xi ,f(xi)g(xi))的点值表示法转换成系数表示法即可得到h(x)的值.

那么如何从点值表示法转换成系数表示法呢? 仔细观察上面的矩阵表达式不难得出:

{ ( x 0 , f ( x 0 ) , ( x 1 , f ( x 1 ) , … , ( x n − 1 , f ( x n − 1 ) } \left\{ (x_0,f(x_0),(x_1,f(x_1), \dots,(x_{n-1},f(x_{n-1}) \right\} { (x0,f(x0),(x1,f(x1),,(xn1,f(xn1)}

将其化为矩阵形式, 有
[ a 0 a 1 ⋮ a n − 1 ] = [ 1 x 0 x 0 2 … x 0 n − 1 1 x 1 x 1 2 … x 1 n − 1 … … … ⋮ … 1 x n − 1 x n − 1 2 … x n − 1 n − 1 ] − 1 [ f ( x 1 ) f ( x 2 ) ⋮ f ( x − 1 ) ] \left[ \begin{array}{l} a_0\\ a_1\\ \vdots \\ a_{n-1} \end{array} \right] = \left[ \begin{array}{l} 1&x_0&x_0^2&\dots&x_{0}^{n-1}\\ 1&x_1&x_1^2&\dots&x_{1}^{n-1}\\ \dots&\dots&\dots&\vdots&\dots\\ 1&x_{n-1}&x_{n-1}^2&\dots&x_{n-1}^{n-1} \end{array} \right]^{-1} \left[ \begin{array}{l} f(x_1)\\ f(x_2)\\ \vdots \\ f(x-1) \end{array} \right] a0a1an1

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值