FFT算法再学以及终于理解

article/2025/10/18 22:35:11

前言

人生如逆旅,我亦是行人。


一、FFT

FFT(Fast Fourier Transformation),中文名快速傅里叶变换,用来 加速多项式乘法 ,就是用来降低算法的时间复杂度的,将时间复杂度由原来的 O(n^2) 变为了O(nlog2n)


二、多项式的表示法

  • FFT 是一个用 O(nlog2n) 的时间将一个用 系数表示法 表示的多项式转换成用 点值表示法 表示的算法设计过程;
  • 多项式的 系数表示点值表示 可以 互相转换;
  1. 系数表示法 转换成 点值表示法,结果相乘:为 求值 过程(DFT
  2. 点值表示法 转换成 系数表示法:为 插值 过程(IDFT

1、系数表示法

  • 一个 n-1 次的 n 项多项式 f(x) 可以表示为:
    在这里插入图片描述
  • 也可以用 每一项的系数 来表示 f(x) ,即

f ( x ) = a 0 , a 1 , a 2 , … , a n f(x) = { a0,a1,a2,…,an } f(x)=a0a1a2an
是这个多项式每一项的系数

2、点值表示法

  • 把多项式放到平面直角坐标系里面,看成一个函数;
  • 把 n 个不同的 x 代入,会得出 n 个不同的 y ,在坐标系内就是 n 个不同的点;
  • 点值表示
    A ( x ) = ( x 0 , f [ x 0 ] ) , ( x 1 , f [ x 1 ] ) , … , ( x n , f [ x n ] ) A(x) = (x_0,f[x_0]),(x_1,f[x_1]),…, (x_n,f[x_n]) A(x)=(x0,f[x0]),(x1,f[x1]),,(xn,f[xn])

三、高精度乘法下两种多项式表示法的区别

  • 对于两个用系数表示的多项式

    我们把它们相乘设两个多项式分别为 A ( x ) , B ( x ) ,我们要枚举 A 每一位的系数与 B 每一位的系数相乘

    那么系数表示法做多项式乘法:时间复杂度 O(n^2)

  • 点值表示法

    只需要 O ( n ) 的时间

    设两个点值多项式分别为:
    在这里插入图片描述

    他们的乘积:
    在这里插入图片描述

    所以这里的时间复杂度只有一个枚举的 O(n)

    • 但是朴素的系数表示法转点值表示法的算法还是 O(n^2)
    • 朴素系数转点值的算法叫DFT(离散傅里叶变换) ,点值转系数叫 IDFT(离散傅里叶逆变换)

四、单位根的性质(!!!)

在这里插入图片描述


五、DFT(离散傅里叶变换)

  • 一定注意从这里开始所有的 n 都默认为 2 的整数次幂

    对于任意系数多项式转点值,当然可以随便取任意 n 个 x 值代入计算,但时间复杂度依然是 O(n^2)

    其实可以代入一组神奇的 x ,代入以后不用做那么多的次方运算

    这些 x 当然不是乱取的,而且取这些 x 值应该就是 傅里叶 的主意了。

  • 规定点值中表示 n 个 x 为 n 个模长为 1 的复数,这 n 个复数不是随机的,而是 单位根。


六、FFT(快速傅里叶变换)

  • 虽然 DFT 能把多项式转换成点值,但是它仍然是暴力代入 n 个数,并没有改变其时间复杂度,其时间复杂度仍是 O(n^2)

  • 因此我们可以考虑利用 单位根的性质 ,加速我们的运算,这就是 快速傅里叶变换(FFT)算法 的提出。

下面是一些步骤:(字写的一般,但写的东西很重要)

在这里插入图片描述

  • 通过上面的步骤,我们就可以知道:
  • 此时的时间复杂度为 O(n)

在这里插入图片描述

注: 因为这一过程一定要求每层都可以分为两个大小相等的部分,所以多项式最高次项一定是 2 的幂数,不是的直接在最高次项补 0 即可。所以实际上的时间复杂度为 O(nlog2n)

A0(x)A1(x) 都是规模缩小了一半的子问题,不断向下递归分治。

n = 1 时,表示只有一个常数项,直接 return


七、IFFT(快速傅里叶逆变换)

将两个多项式从系数表示法转化成点值表示法相乘后,还要将结果从点值表示法转化为系数表示法,也就是 IFFT(快速傅里叶逆变换)

重要:

  • 把一个多项式 A(x) 的离散傅里叶变换结果(点值)作为另一个多项式 B(x) 的系数,然后再取 单位根的倒数(就是单位根的共轭复数) 作为 x 代入 B(x) 中,得到的每一项再除以 n ,最后的结果就是 A(x) 的各项系数。
  • 这就是 傅里叶变换的逆变换 ,相当于在 FFT 的基础上在进行一次 FFT

八、最后的优化(迭代FFT)

在进行FFT时,我们要把各个系数不断分组并放到两侧,一个系数原来的位置和最终的位置的规律如下:
在这里插入图片描述

  • 将每个位置用二进制表现出来,位置 x 上的数,最后所在的位置为:x 二进制翻转后得到的数字;
  • 例如:
  • 4(100)最后所在位置为:1(001);
  • 5(101)最后所在位置为:5(101),不变;
  • 3(011)最后所在位置为:6(110)。
  • 所以我们先把每个数放到最后的位置上,然后不断向上还原,同时求出点值表示就可以啦。
  • 迭代版的 FFT 比之前的递归版本的更快了,真 :O(nlog2n)

九、代码实现 FFT(C++):

#include <bits/stdc++.h>
using namespace std;
// complex是stl自带的定义复数的容器
typedef complex<double> cp;
#define N 2097153
// pie表示圆周率π
const double pie = acos(-1);
int n;
cp a[N], b[N];
int rev[N], ans[N];
char s1[N], s2[N];
//读入优化
int read()
{int sum = 0, f = 1;char ch = getchar();while (ch > '9' || ch < '0'){if (ch == '-')f = -1;ch = getchar();}while (ch >= '0' && ch <= '9'){sum = (sum << 3) + (sum << 1) + ch - '0';ch = getchar();}return sum * f;
}
//初始化每个位置最终到达的位置
void init(int k)
{int len = 1 << k;for (int i = 0; i < len; i++)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1));
}
// a表示要操作的系数,n表示序列长度
//若flag为1,则表示FFT,为-1则为IFFT(需要求倒数)
void fft(cp *a, int n, int flag)
{for (int i = 0; i < n; i++){// i小于rev[i]时才交换,防止同一个元素交换两次,回到它原来的位置。if (i < rev[i])swap(a[i], a[rev[i]]);}for (int h = 1; h < n; h *= 2) // h是准备合并序列的长度的二分之一{cp wn = exp(cp(0, flag * pie / h)); //求单位根w_n^1for (int j = 0; j < n; j += h * 2)  // j表示合并到了哪一位{cp w(1, 0);for (int k = j; k < j + h; k++) //只扫左半部分,得到右半部分的答案{cp x = a[k];cp y = w * a[k + h];a[k] = x + y; //这两步是蝴蝶变换a[k + h] = x - y;w *= wn; //求w_n^k}}}//判断是否是FFT还是IFFTif (flag == -1)for (int i = 0; i < n; i++)a[i] /= n;
}
int main()
{n = read();scanf("%s%s", s1, s2);//读入的数的每一位看成多项式的一项,保存在复数的实部for (int i = 0; i < n; i++)a[i] = (double)(s1[n - i - 1] - '0');for (int i = 0; i < n; i++)b[i] = (double)(s2[n - i - 1] - '0');// k表示转化成二进制的位数int k = 1, s = 2;while ((1 << k) < 2 * n - 1)k++, s <<= 1;init(k);// FFT 把a的系数表示转化为点值表示fft(a, s, 1);// FFT 把b的系数表示转化为点值表示fft(b, s, 1);// FFT 两个多项式的点值表示相乘for (int i = 0; i < s; i++)a[i] *= b[i];// IFFT 把这个点值表示转化为系数表示fft(a, s, -1);//保存答案的每一位(注意进位)for (int i = 0; i < s; i++){//取实数四舍五入,此时虚数部分应当为0或由于浮点误差接近0ans[i] += (int)(a[i].real() + 0.5);ans[i + 1] += ans[i] / 10;ans[i] %= 10;}while (!ans[s] && s > -1)s--;if (s == -1)printf("0");elsefor (int i = s; i >= 0; i--)printf("%d", ans[i]);return 0;
}

终于搞定了 FFT 这个“优美”的算法了,学了好几天的,总算弄懂原理了。✿✿ヽ(°▽°)ノ✿


http://chatgpt.dhexx.cn/article/QFPSC4dI.shtml

相关文章

十分简明易懂的FFT(快速傅里叶变换)

FFT前言 快速傅里叶变换 (fast Fourier transform),即利用计算机计算离散傅里叶变换&#xff08;DFT)的高效、快速计算方法的统称&#xff0c;简称FFT。快速傅里叶变换是1965年由J.W.库利和T.W.图基提出的。采用这种算法能使计算机计算离散傅里叶变换所需要的乘法次数大为减少&…

第四章快速傅里叶变换FFT

一、基2FFT算法 1.直接计算DFT的特点 对于N点DFT的乘法和加法运算次数均为N^2(运算量较大)减少运算量的基本途径&#xff1a;将N点DFT分解成多个较短的DFT旋转因子具有 周期性&#xff1a; 对称性&#xff1a;或又或者 2.时域抽取法基2FFT基本原理 分类&#xff1a;基2FFT分…

数学专题小结:FFT算法

快速傅里叶变换(FFT,Fast Fourier Transform)是信号处理的常用手段,可以把时域信号变成频域信号,时域的卷积运算对应于频域就成了简单的乘法运算。由于两个多项式的乘积,其系数的运算实际上也是一种卷积运算,因此可以用FFT来计算多项式的乘法。网上关于FFT算法的讲解大多…

转:fft算法(快速傅里叶变换算法)

FFT (Fast Fourier Transform) 是一种快速傅里叶变换算法。它是用来将一个信号从时域转换到频域的算法。这个算法通过分治策略&#xff0c;将一个长度为 N 的复数序列分解成 N/2 个长度为 2 的复数序列&#xff0c;然后对这些小的序列分别进行 FFT 计算。 最简单的 FFT 算法是暴…

快速傅里叶变换(FFT)算法学习

前言 人生如逆旅&#xff0c;我亦是行人。 一、介绍 算法的世界多么广大&#xff0c;我们可以将算法大致分为两类&#xff1a; 第一类是较为有用的算法&#xff1a;比如一些经典的图算法&#xff0c;像 DFS 和 BFS&#xff08;深度 / 广度优先算法&#xff09;&#xff0c;这些…

FFT算法讲解——麻麻我终于会FFT了!

FFT——快速傅里叶变换 这块不写东西空荡荡的&#xff0c;我决定还是把FFT的定义给贴上吧 FFT&#xff08;Fast Fourier Transformation&#xff09;是离散傅氏变换&#xff08;DFT&#xff09;的快速算法。即为快速傅氏变换。它是根据离散傅氏变换的奇、偶、虚、实等特性&…

怎么计算网站流量?

如何计算网站的流量呢&#xff1f;在这华仔给大家分享一个如何计算流量的算法&#xff1a; 举个栗子&#xff1a;1G1024M&#xff0c;10G就是101024M10240M. 一个1M的文件被下载1000次的流量约为1G;被下载10000次的流量约为10G. 假如你每月的网站流量为10G&#xff0c;那10G的流…

CDN流量是什么,怎么计算?

CDN流量通俗来讲就是使用CDN加速时&#xff0c;网络加速会产生一个数据使用量&#xff0c;到达某一个时段&#xff0c;统计出这个时段使用的量&#xff0c;也就是CDN流量&#xff0c;和网站流量的使用很像。 随着互联网的发展&#xff0c;用户在使用网络时对网站的浏览速度和…

流量计算器

为所做的工作处于初始开发的阶段&#xff0c;所以数据一直在变化&#xff0c;导致1s的流量大小一直也在变化。每次都需要手动根据新的参数进行计算&#xff0c;真的好烦。 所以呢&#xff0c;作为一个程序员&#xff0c;能让程序做的事情&#xff0c;自己就不要动手了呀&#x…

Flink1.14相关-3.数据流量计算

1. 前言 使用环境 Flink1.14.6Centos7.9Java8 Flink1.14.6安装部署测试参考&#xff1a;参考链接 2 .数据采集 2.1 信号监听 需要监听文件夹下的新文件产生&#xff0c;并且数据库中的值未更新时才发送消息通知后续模块开始采集数据。【后面需要重新搭建监听部分和判断部分…

适应多场景的客流量统计-人流量统计算法

在商场、展厅、景区等受人流量影响较大的场所&#xff0c;流量统计算法可以快速获取流量数据和动态趋势&#xff0c;辅助评估店铺和部分活动的效果&#xff0c;帮助商业决策。另外&#xff0c;在地铁站、火车站、机场等公共场所。实时检测人数可以及时预警高密度人群&#xff0…

网站的服务器带宽计算,服务器带宽和流量计算方式

服务器带宽和流量计算方式。网站流量和带宽该怎么计算&#xff0c;给一些参照数据信息&#xff0c;由于不清楚流量和带宽是怎么计算的&#xff0c;因此不清楚用多宽的带宽更有效、更节省资产! 网站服务器上最好是安装流量统计手机软件(强烈推荐应用DUMeter)&#xff0c;假如流量…

博途1200/1500PLC累计流量计算FB(SCL算法详解+优化)

在编写这篇博客之前其实已经写过一篇SMART S7-200PLC的流量累计的应用文章,由于很多朋友咨询博途PLC下的流量累计实现算法。今天我们以博途PLC的开发环境为例详细讲解算法的实现原理和注意事项同时给出算法的优化方法。受水平和能力所限,文中难免出现错误和不足之处,诚恳的欢…

阿里云轻量应用服务器流量计算方法

阿里云轻量应用服务器套餐有峰值带宽限制每月流量的&#xff0c;还有固定带宽的&#xff0c;阿里云轻量应用服务器流量是怎么计算的&#xff1f;阿里云轻量应用服务器来说说不同套餐下轻量服务器流量计算方法&#xff1a; 轻量应用服务器带宽套餐和流量套餐 阿里云轻量应用服…

物联网GPRS模块流量计算

物联网GPRS模块流量计算 MQTT(消息队列遥测传输) 是ISO 标准下一个基于TCP/IP的消息发布/订阅传输协议。 一、TCP消耗流量计算 以太网数据包结构&#xff1a; 以太网首部 IP首部 TCP首部 APPL首部 用户数据 以太网尾部 以太网首部为14个字节 IP首部为20个字节 TCP首部…

恒容容器放气的瞬时流量的计算

有时候&#xff0c;你会遇到一个问题&#xff0c;该问题的描述如下&#xff1a; 你有一个已知体积的容器&#xff0c;设容器体积为&#xff0c;里面装有一定压力(初始压力)的气体&#xff0c;如空气或氢气等&#xff0c;设初始压力为&#xff0c;容器出口连接着一个阀门开关&am…

阿里云服务器公网带宽流量是怎么计算的?

阿里云服务器流量如何计算&#xff1f;云服务器出流量和入流量都要计算吗&#xff1f;不是&#xff0c;只计算云服务器公网出方向流量&#xff0c;阿里云服务器内网流量和公网出方向流量都是免费的&#xff0c;护云盾来详细说下阿里云服务器流量计算及流量收费说明&#xff1a;…

计算机网络-流量强度

若R链路带宽&#xff08;链路宽度&#xff09;&#xff0c;L分组长度&#xff08;一个分组的大小&#xff09;&#xff0c;a分组到达队列的平均速率&#xff08;分组数量&#xff09;&#xff0c;流量强度公式 &#xff1a;I La/R 举例理解&#xff1a; 当汽车排队从关卡上桥…

腾讯云服务器带宽计费模式按流量内网、外网出入流量计算说明

腾讯云服务器公网带宽计费模式按使用流量计费&#xff0c;云服务器对内或对外产生的流量如何计算&#xff1f;云服务器出方向&#xff08;下行流量&#xff09;和入方向&#xff08;上行流量&#xff09;怎么计算&#xff1f;腾讯云百科来详细说下腾讯云服务器按使用流量计算说…

计算视频流量

码率也可以叫比特率&#xff0c;就是一种音乐每秒播放的数据量&#xff0c;单位用bit表示&#xff0c;也就是二进制位。 bps就是比特率。b就是比特&#xff08;bit&#xff09;&#xff0c;s就是秒&#xff08;second&#xff09;&#xff0c;p就是每&#xff08;per&#xff0…