超大數乘法---FFT


思路:

   算法導論第30章有詳細說明。此處只是簡略說明其主要的步驟。

一個知識點是:

  A(x)=a0+a1x+a2x2+a3x3+……+an-1xn-1

 A[0](x)=a0+a2x+a4x2+……+an-2xn/2-1

 A[1](x)=a1+a3x+a5x2+……+an-1xn/2-1

 

 A[0](x2)+x*A[1](x2)=A(x)  

以上是 二進制平攤反轉置換跟求和的主要式子。

多項式有兩種表示形式:點值表示,系數表示。

快速FFT主要有以下四點:

   1. 使次數界(上界)增加一倍。A(x)、B(x)的長度擴充到2*n

   2. 求值。主要是求點值表示A(x)、B(x)的點值表示

   3. 點乘。C(x)=A(x)*B(x)

   4. 插值。對C(x)進行插值,求出其系數表示。


 代碼如下:

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #define Pi acos(-1.0)//定義Pi的值
  5 #define N 200000
  6 using namespace std;
  7 struct complex //定義復數結構體
  8 {
  9   double re,im;
 10   complex(double r=0.0,double i=0.0)
 11   {  re=r,im=i; }  //初始化
//定義三種運算
12 complex operator +(complex o) 13 { return complex(re+o.re,im+o.im);} 14 complex operator -(complex o) 15 { return complex(re-o.re,im-o.im);} 16 complex operator *(complex o) 17 { return complex(re*o.re-im*o.im,re*o.im+im*o.re);} 18 }x1[N],x2[N]; 19 char a[N/2],b[N/2]; 20 int sum[N]; //存儲最后的結果 21 22 void BRC(complex *y,int len)//二進制反轉倒置 23 { 24 int i,j,k; 25 for(i=1,j=len/2;i<len-1;i++) 26 { 27 if(i<j)swap(y[i],y[j]);//i<j保證只交換一次 28 k=len/2; 29 while(j>=k) 30 { 31 j-=k;k=k/2; 32 } 33 if(j<k)j+=k; 34 } 35 } 36 void FFT(complex *y,int len ,double on)//on=1表示順,-1表示逆 37 { 38 int i,j,k,h; 39 complex u,t; 40 BRC(y,len); 41 for(h=2;h<=len;h<<=1)//控制層數 42 { 43 //初始化單位復根 44 complex wn(cos(on*2*Pi/h),sin(on*2*Pi/h)); 45 for(j=0;j<len;j+=h)//控制起始下標 46 { 47 //初始化螺旋因子 48 complex w(1,0); 49 for(k=j;k<j+h/2;k++) 50 { 51 u=y[k]; 52 t=w*y[k+h/2]; 53 y[k]=u+t; 54 y[k+h/2]=u-t; 55 w=w*wn;//更新螺旋因子 56 } 57 } 58 } 59 if(on==-1) 60 for(i=0;i<len;i++) //逆FFT(IDFT) 61 y[i].re/=len; 62 63 } 64 int main() 65 { 66 int len1,len2,len,i; 67 while(scanf("%s%s",a,b)!=EOF) 68 { 69 len1=strlen(a); 70 len2=strlen(b); 71 len=1; 72 //擴充次數界至2*n 73 while(len<2*len1||len<2*len2)len<<=1;//右移相當於len=len*2 74 //倒置存儲 75 for(i=0;i<len1;i++) 76 { x1[i].re=a[len1-1-i]-'0';x1[i].im=0.0;} 77 for(;i<len1;i++) //多余次數界初始化為0 78 {x1[i].re=x1[i].im=0.0;} 79 for(i=0;i<len2;i++) 80 { x2[i].re=b[len2-1-i]-'0';x2[i].im=0.0;} 81 for(;i<len2;i++) //多余次數界初始化為0 82 {x2[i].re=x2[i].im=0.0;} 83 //FFT求值 84 FFT(x1,len,1);//FFT(a) 1表示順 -1表示逆 85 FFT(x2,len,1);//FFT(b) 86 //點乘,結果存入x1 87 for(i=0;i<len;i++) 88 x1[i]=x1[i]*x2[i]; 89 //插值,逆FFT(IDTF) 90 FFT(x1,len,-1); 91 92 //細節處理 93 for(i=0;i<len;i++) 94 sum[i]=x1[i].re+0.5;//四舍五入 95 for(i=0;i<len;i++) //進位 96 { 97 sum[i+1]+=sum[i]/10; 98 sum[i]%=10; 99 } 100 //輸出 101 len=len1+len2-1; 102 while(sum[len]<=0&&len>0)len--;//檢索最高位 103 for(i=len;i>=0;i--) //倒序輸出 104 cout<<sum[i]; 105 cout<<endl; 106 } 107 return 0; 108 }

 

值得注意的細節:a,b輸入的是字符串,x1,x2的re中存儲的是double類型的數據。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM