美文网首页
FFT快速傅里叶变换

FFT快速傅里叶变换

作者: 1QzUPm_09F | 来源:发表于2017-08-23 09:34 被阅读0次
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <complex>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef complex<double> cp;                     //complex库
    const double PI = acos(-1);
    
    void fft(cp *a,int n,int flag)                  //作用:求出a的点值表达,存进a
    {
        int i;
        cp a0[n/2+1],a1[n/2+1];
    
        if(n==1) return;
        cp w_n(cos(2*PI/n),sin(flag*2*PI/n));   //flag=1:求值  flag=2:插值
        cp w(1,0);
    
        for(i=0; i<n/2; i++) a0[i]=a[i*2],a1[i]=a[i*2+1];   //分治
    
        fft(a0,n/2,flag);
        fft(a1,n/2,flag);
    
        for(i=0; i<n/2; i++)
        {
            a[i]=a0[i]+w*a1[i];
            a[i+n/2]=a0[i]-w*a1[i];
            w=w*w_n;                                //递推单位复数根
        }
    
    }
    
    cp x[300005]= {0},y[300005]= {0};
    
    char arr1[100005], arr2[100005];
    int ans[200005];
    
    int main()
    {
        while(~scanf("%s%s", arr1, arr2))
        {
            for(int i=0; i<300005; i++) x[i]=cp(0, 0);
            for(int i=0; i<300005; i++) y[i]=cp(0, 0);
    
            int n, m, i;
            n=strlen(arr1)-1;
            m=strlen(arr2)-1;
    
            for(i=0; i<=n; i++) x[i]=cp(arr1[n-i]-'0', 0);
            for(i=0; i<=m; i++) y[i]=cp(arr2[m-i]-'0', 0);
            m+=n;
            for(n=1; n<=m; n=n*2);
    
            fft(x,n,1);                                 //求值
            fft(y,n,1);                                 //求值
    
            for(i=0; i<n; i++) x[i]=x[i]*y[i];          //点值乘法
            fft(x,n,-1);                                //插值
    
            memset(ans, 0, sizeof(ans));
    
            for(i=0; i<n || ans[i]; i++)
            {
                ans[i]+=(x[i].real()/n+0.5);
                ans[i+1]+=(ans[i]/10);
                ans[i]%=10;
            }
    
            while(i>0 && !ans[i])i--;
            for(; i>=0; i--) printf("%d", ans[i]);
            printf("\n");
        }
        return 0;
    }
    
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <complex>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const double PI = acos(-1);
    
    struct Complex
    {
        double real, image;
        Complex(double real=0.0, double image=0.0): real(real), image(image) {}
        Complex operator +(const Complex &b)
        {
            return Complex(real+b.real,image+b.image);
        }
        Complex operator -(const Complex &b)
        {
            return Complex(real-b.real,image-b.image);
        }
        Complex operator *(const Complex &b)
        {
            return Complex(real*b.real-image*b.image,real*b.image+image*b.real);
        }
    };
    
    Complex x[300005]= {0},y[300005]= {0};
    char arr1[100005], arr2[100005];
    int ans[200005];
    int n, m;
    
    void reverse(Complex a[],int n) //对长度为的复数序列a进行DFT和IDFT之前必要的反转变换操作(比特反转),n一定是2的幂次
    {
        for(int i=1,j=n/2,k; i<n-1; i++)
        {
            if(i<j) swap(a[i],a[j]);
            k=n/2;
            while(j>=k)
            {
                j-=k;
                k/=2;
            }
            if(j<k) j+=k;
        }
    }
    
    void fft(Complex *a,int n,int flag) //flag=1是求值,flag=-1是插值
    {
        reverse(a,n);
        for(int i=1; i<n; i<<=1) //i=该层的相邻结点之间编号之差,logn次迭代模拟,自底向上
        {
            Complex wn=Complex(cos(PI/i),flag*sin(PI/i));
            for(int j=0; j<n; j+=(i<<1)) //编号为j的结点
            {
                Complex w=Complex(1,0);
                for(int k=0; k<i; k++,w=w*wn)
                {
                    Complex x=a[j+k],y=w*a[j+k+i]; //x和y是当前节点左右递归下去后得到的fft值,当然,y(右儿子,奇数项)的fft值要乘上一个w
                    a[j+k]=x+y;
                    a[j+k+i]=x-y;
                }
            }
        }
        if(flag==-1) //如果是插值,还得在前面加个1/n的系数
            for(int i=0; i<n; i++)
                a[i].real/=n;
    }
    
    void Fast_Fourier_Transform(char *arr1, char *arr2)
    {
        int i;
        n=strlen(arr1)-1;
        m=strlen(arr2)-1;
    
        for(i=0; i<=n; i++) x[i]=Complex(arr1[n-i]-'0', 0);
        for(i=0; i<=m; i++) y[i]=Complex(arr2[m-i]-'0', 0);
        m+=n;
        for(n=1; n<=m; n=n*2);
    
        fft(x,n,1);                                 //求值
        fft(y,n,1);                                 //求值
    
        for(i=0; i<n; i++) x[i]=x[i]*y[i];          //点值乘法
        fft(x,n,-1);                                //插值
    }
    
    int main()
    {
        while(~scanf("%s%s", arr1, arr2))
        {
            int i;
            for(i=0; i<300005; i++) x[i]=Complex(0, 0);
            for(i=0; i<300005; i++) y[i]=Complex(0, 0);
    
            Fast_Fourier_Transform(arr1, arr2);
    
            memset(ans, 0, sizeof(ans));
    
            for(i=0; i<n || ans[i]; i++)
            {
                ans[i]+=(x[i].real+0.5);
                ans[i+1]+=(ans[i]/10);
                ans[i]%=10;
            }
    
            while(i>0 && !ans[i])i--;
            for(; i>=0; i--) printf("%d", ans[i]);
            printf("\n");
        }
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:FFT快速傅里叶变换

          本文链接:https://www.haomeiwen.com/subject/lgxddxtx.html