一些思考和FFT代码

今天干活的时候总是力不从心,遇见各种各样的问题,最后还是靠同事帮忙,还没解决,明天去解决一下。

读文档的能力实在太重要了,我在浏览器搜啊搜、在gpt问啊问,最后还是不如官方文档好使,能够快速的看懂官方文档,并上手实践,与会写代码一样重要,工程上的工具其实已经很成熟了,各种框架、库。一般的工作人员只需要懂怎么用好这些框架和库就行了。不需要去搞什么科研,研究这个那个模型,这个那个算法。纯搞算法也行,那就是上游产业,像Nvidia的计算库、像C++、java、python、pytorch、tensorflow这样的编程语言和框架,那就很牛。搞芯片也是,也特别牛。算法,要是不是搞研究,是偏工程的话,那就和开发没什么区别,可能需要稍微看下原理什么的,不过不看也行,能根据使用文档,把任务完成就行了,至于其他的都不重要。又不是发论文。

来钱快的意义不大,很牛的研究不一定能落地,不一定能挣钱。

傅里叶变换

'任何连续周期信号都可以由一组适当的正弦曲线组合而成'

感觉很像傅里叶级数?有木有。

ref2

时域和频域

这里只是浅浅的看了一下FT的内容,因为FT是连续的,计算机只能处理离散的数据,所以实际上大家用的是DFT,离散的傅里叶变换。

离散的傅里叶变换逻辑上是:先对信号在时域上采样,然后傅里叶变换,再在频域上进行采样。

而DFT实际上达到的效果是一样的,不过运算的逻辑不同。

FFT发明之后,通信界才百花齐放,走向新的繁荣。没有FFT,傅里叶变换那么慢,怎么解? 

FFT没怎么仔细看,简单理解就是用点代替函数表示,把$O(n^2)$简化为O(nlogn)

代码很简单,让人感受到数学的简洁与美丽!ref

#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;
}
//初始化每个位置最终到达的位置 
{
    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^1 
	 for(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还是IFFT 
	 if(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或由于浮点误差接近0
	ans[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");
	else
	for(int i=s;i>=0;i--)
	printf("%d",ans[i]);
	return 0;
}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值