#include <stdio.h> #include <stdlib.h> #include <math.h> typedef struct { double r ; double i ; } ad_t ; /* ===== fft ======== */ void *fft(int nx ,ad_t a[]) { int i, k, m, n; double tmpr, tmpi, r, cosw, sinw; n = 1<<nx; r = -M_PI / (double)n; for(m = n/2; m > 0 ; m /= 2 ) { r *= 2; for(k = 0 ; k < m; k++) { cosw = cos(r*(double)k); sinw = sin(r*(double)k); for(i= k ; i < n; i += m*2) { tmpr = a[i].r - a[m+i].r; tmpi = a[i].i - a[m+i].i; a[i].r = a[i].r + a[m+i].r; a[i].i = a[i].i + a[m+i].i; a[m+i].r = tmpr * cosw - tmpi * sinw; a[m+i].i = tmpi * cosw + tmpr * sinw; } } } return; } /* ===== ifft ======== */ void *ifft(int nx,ad_t a[]) { int i, k, m,n; double tmpr, tmpi, r, cosw, sinw; n = 1<< nx ; r = M_PI ; for(m = 1; m < n ; m *= 2 ) { for(k = 0; k < m; k++) { cosw = cos(r*(double)k); sinw = sin(r*(double)k); for(i= k ; i < n; i += m*2) { tmpr = cosw * a[m+i].r - sinw * a[m+i].i; tmpi = cosw * a[m+i].i + sinw * a[m+i].r; a[m+i].r = a[i].r - tmpr ; a[m+i].i = a[i].i - tmpi; a[i].r = a[i].r + tmpr ; a[i].i = a[i].i + tmpi; } } r *= 0.5; } return; } /* a * b -> a */ void *ri_mul(int nx,ad_t a[],ad_t b[]) { int m ; double tmpa , tmpb ; a[0].r = a[0].r*b[0].r; a[0].i = a[0].i*b[0].i; for(m=1;m<(1<<nx);m++){ tmpa = a[m].r; tmpb = b[m].r; a[m].r = tmpa*tmpb - a[m].i*b[m].i; a[m].i = tmpa*b[m].i + a[m].i*tmpb; } } /* スケーリングと繰越 n-2 -> 0 方向 */ void *ri_carry(int nx,ad_t a[],int redex) { double pn,tmp; int n , m; long car , t; n = 1<<nx ; pn = 1.0/(double)n; car = 0 ; for(m=n-2;m>=0;m--){ tmp = a[m].r*pn + (double)car ; if( tmp >= 0.0 ){ t = (long)(tmp+0.5) ; car = t / redex ; a[m].r =(double)( t % redex ); }else{ t = (long)(tmp-0.5) ; car = t / redex - 1; a[m].r =(double)( t % redex + redex ); } } a[n-1].r=(double)car; } /* スケーリングと繰越 0 -> n-2 方向 */ void *ri_carry_r(int nx,ad_t a[],int redex) { double pn,tmp; int n , m; long car , t; n = 1<<nx ; pn = 1.0/(double)n; car = 0 ; for(m=0;m<n-1;m++){ tmp = a[m].r*pn + (double)car ; if( tmp >= 0.0 ){ t = (long)(tmp+0.5) ; car = t / redex ; a[m].r =(double)( t % redex ); }else{ t = (long)(tmp-0.5) ; car = t / redex - 1; a[m].r =(double)( t % redex + redex ); } } a[n-1].r=(double)car; } /* 任意の値のビット反転 */ inline unsigned int bitrv_v(int nx, unsigned int a ) { a = ((a & 0x55555555)<< 1 ) | ((a >> 1) & 0x55555555 ); a = ((a & 0x33333333)<< 2 ) | ((a >> 2) & 0x33333333 ); a = ((a & 0x0f0f0f0f)<< 4 ) | ((a >> 4) & 0x0f0f0f0f ); a = ((a & 0x00ff00ff)<< 8 ) | ((a >> 8) & 0x00ff00ff ); a = ((a & 0x0000ffff)<<16 ) | ((a >>16) & 0x0000ffff ); return (a >> (32-nx)) ; } /* ビット反転 インクリメンタル */ inline unsigned int inc_rvbit(int nx , unsigned int a ) { unsigned int rb ; rb = 1<<nx; do { rb >>= 1; a ^= rb; /* xor は、繰越なしで1bitの足し算したものと同じ */ } while ( rb > a ); /* xor の結果が、1の時終わり */ return a; } /* ビット反転位置のデータ入れ替え */ void *bitrv(int nx , ad_t a[]) { int i ,j; int nm1 , nh ; ad_t t; nh = 1<<(nx-1); nm1 = (1<<nx) -1 ; j = 0 ; for (i = 1; i < nh ; i++) { j = inc_rvbit(nx , j ); if (j > i) { t = a[j]; a[j] = a[i]; a[i] = t; if( j < nh ){ t = a[nm1-j]; a[nm1-j]=a[nm1-i]; a[nm1-i]=t; } } } } |
以下動作確認
input data n = 16 = 1<<4 0 a[ 0].r = 2.000000 a[ 0].i = 0.000000 b[ 0].r = 9.000000 b[ 0].i = 0.000000 1 a[ 1].r = 1.000000 a[ 1].i = 0.000000 b[ 1].r = 8.000000 b[ 1].i = 0.000000 2 a[ 2].r = 2.000000 a[ 2].i = 0.000000 b[ 2].r = 7.000000 b[ 2].i = 0.000000 3 a[ 3].r = 3.000000 a[ 3].i = 0.000000 b[ 3].r = 6.000000 b[ 3].i = 0.000000 4 a[ 4].r = 4.000000 a[ 4].i = 0.000000 b[ 4].r = 5.000000 b[ 4].i = 0.000000 5 a[ 5].r = 5.000000 a[ 5].i = 0.000000 b[ 5].r = 4.000000 b[ 5].i = 0.000000 6 a[ 6].r = 6.000000 a[ 6].i = 0.000000 b[ 6].r = 2.000000 b[ 6].i = 0.000000 7 a[ 7].r = 7.000000 a[ 7].i = 0.000000 b[ 7].r = 3.000000 b[ 7].i = 0.000000 8 a[ 8].r = 0.000000 a[ 8].i = 0.000000 b[ 8].r = 0.000000 b[ 8].i = 0.000000 9 a[ 9].r = 0.000000 a[ 9].i = 0.000000 b[ 9].r = 0.000000 b[ 9].i = 0.000000 10 a[10].r = 0.000000 a[10].i = 0.000000 b[10].r = 0.000000 b[10].i = 0.000000 11 a[11].r = 0.000000 a[11].i = 0.000000 b[11].r = 0.000000 b[11].i = 0.000000 12 a[12].r = 0.000000 a[12].i = 0.000000 b[12].r = 0.000000 b[12].i = 0.000000 13 a[13].r = 0.000000 a[13].i = 0.000000 b[13].r = 0.000000 b[13].i = 0.000000 14 a[14].r = 0.000000 a[14].i = 0.000000 b[14].r = 0.000000 b[14].i = 0.000000 15 a[15].r = 0.000000 a[15].i = 0.000000 b[15].r = 0.000000 b[15].i = 0.000000 fft(nx,a) fft(nx,b) 0 a[ 0].r = 30.000000 a[ 0].i = 0.000000 b[ 0].r = 44.000000 b[ 0].i = 0.000000 1 a[ 8].r = -7.137071 a[ 8].i = -20.109358 b[ 8].r = 17.920298 b[ 8].i = -24.812274 2 a[ 4].r = -2.000000 a[ 4].i = 9.656854 b[ 4].r = 4.707107 b[ 4].i = -9.949747 3 a[12].r = 4.380086 a[12].i = -5.986423 b[12].r = 5.530124 b[12].i = -7.699802 4 a[ 2].r = -2.000000 a[ 2].i = 4.000000 b[ 2].r = 5.000000 b[ 2].i = -3.000000 5 a[10].r = 5.276769 a[10].i = -2.672715 b[10].r = 5.398808 b[10].i = -4.971880 6 a[ 6].r = -2.000000 a[ 6].i = 1.656854 b[ 6].r = 3.292893 b[ 6].i = 0.050253 7 a[14].r = 5.480217 a[14].i = -0.795649 b[14].r = 7.150769 b[14].i = -2.084352 8 a[ 1].r = -2.000000 a[ 1].i = 0.000000 b[ 1].r = 2.000000 b[ 1].i = 0.000000 9 a[ 9].r = 5.480217 a[ 9].i = 0.795649 b[ 9].r = 7.150769 b[ 9].i = 2.084352 10 a[ 5].r = -2.000000 a[ 5].i = -1.656854 b[ 5].r = 3.292893 b[ 5].i = -0.050253 11 a[13].r = 5.276769 a[13].i = 2.672715 b[13].r = 5.398808 b[13].i = 4.971880 12 a[ 3].r = -2.000000 a[ 3].i = -4.000000 b[ 3].r = 5.000000 b[ 3].i = 3.000000 13 a[11].r = 4.380086 a[11].i = 5.986423 b[11].r = 5.530124 b[11].i = 7.699802 14 a[ 7].r = -2.000000 a[ 7].i = -9.656854 b[ 7].r = 4.707107 b[ 7].i = 9.949747 15 a[15].r = -7.137071 a[15].i = 20.109358 b[15].r = 17.920298 b[15].i = 24.812274 ri_mul(nx,a,b) 0 a[ 0].r = 1320.000000 a[ 0].i = 0.000000 1 a[ 8].r = -626.857348 a[ 8].i = -183.278730 2 a[ 4].r = 86.669048 a[ 4].i = 65.355339 3 a[12].r = -21.871852 a[12].i = -66.831453 4 a[ 2].r = 2.000000 a[ 2].i = 26.000000 5 a[10].r = 15.199846 a[10].i = -40.664931 6 a[ 6].r = -6.669048 a[ 6].i = 5.355339 7 a[14].r = 37.529354 a[14].i = -17.112207 8 a[ 1].r = -4.000000 a[ 1].i = 0.000000 9 a[ 9].r = 37.529354 a[ 9].i = 17.112207 10 a[ 5].r = -6.669048 a[ 5].i = -5.355339 11 a[13].r = 15.199846 a[13].i = 40.664931 12 a[ 3].r = 2.000000 a[ 3].i = -26.000000 13 a[11].r = -21.871852 a[11].i = 66.831453 14 a[ 7].r = 86.669048 a[ 7].i = -65.355339 15 a[15].r = -626.857348 a[15].i = 183.278730 ifft(nx,a) 0 a[ 0].r = 288.000000 a[ 0].i = -0.000000 1 a[ 1].r = 400.000000 a[ 1].i = -0.000000 2 a[ 2].r = 640.000000 a[ 2].i = -0.000000 3 a[ 3].r = 992.000000 a[ 3].i = 0.000000 4 a[ 4].r = 1440.000000 a[ 4].i = -0.000000 5 a[ 5].r = 1968.000000 a[ 5].i = 0.000000 6 a[ 6].r = 2528.000000 a[ 6].i = -0.000000 7 a[ 7].r = 3216.000000 a[ 7].i = -0.000000 8 a[ 8].r = 2672.000000 a[ 8].i = 0.000000 9 a[ 9].r = 2208.000000 a[ 9].i = 0.000000 10 a[10].r = 1744.000000 a[10].i = 0.000000 11 a[11].r = 1296.000000 a[11].i = -0.000000 12 a[12].r = 880.000000 a[12].i = -0.000000 13 a[13].r = 512.000000 a[13].i = -0.000000 14 a[14].r = 336.000000 a[14].i = -0.000000 15 a[15].r = -0.000000 a[15].i = 0.000000 copy a -> b ri_carry(nx,a,10) ri_carry_r(nx,b,10) 0 a[15].r = 2.000000 a[15].i = 0.000000 b[15].r = 2.000000 b[15].i = 0.000000 1 a[ 0].r = 0.000000 a[ 0].i = -0.000000 b[14].r = 4.000000 b[14].i = -0.000000 2 a[ 1].r = 9.000000 a[ 1].i = -0.000000 b[13].r = 8.000000 b[13].i = -0.000000 3 a[ 2].r = 7.000000 a[ 2].i = -0.000000 b[12].r = 4.000000 b[12].i = -0.000000 4 a[ 3].r = 2.000000 a[ 3].i = 0.000000 b[11].r = 3.000000 b[11].i = -0.000000 5 a[ 4].r = 4.000000 a[ 4].i = -0.000000 b[10].r = 4.000000 b[10].i = 0.000000 6 a[ 5].r = 0.000000 a[ 5].i = 0.000000 b[ 9].r = 6.000000 b[ 9].i = 0.000000 7 a[ 6].r = 9.000000 a[ 6].i = -0.000000 b[ 8].r = 8.000000 b[ 8].i = 0.000000 8 a[ 7].r = 9.000000 a[ 7].i = -0.000000 b[ 7].r = 8.000000 b[ 7].i = -0.000000 9 a[ 8].r = 1.000000 a[ 8].i = 0.000000 b[ 6].r = 1.000000 b[ 6].i = -0.000000 10 a[ 9].r = 9.000000 a[ 9].i = 0.000000 b[ 5].r = 2.000000 b[ 5].i = 0.000000 11 a[10].r = 7.000000 a[10].i = 0.000000 b[ 4].r = 6.000000 b[ 4].i = -0.000000 12 a[11].r = 6.000000 a[11].i = -0.000000 b[ 3].r = 6.000000 b[ 3].i = 0.000000 13 a[12].r = 8.000000 a[12].i = -0.000000 b[ 2].r = 2.000000 b[ 2].i = -0.000000 14 a[13].r = 4.000000 a[13].i = -0.000000 b[ 1].r = 6.000000 b[ 1].i = -0.000000 15 a[14].r = 1.000000 a[14].i = -0.000000 b[ 0].r = 8.000000 b[ 0].i = -0.000000 a 21234567 * 98765423 = 2097240991976841 b 76543212 * 32456789 = 2484346881266268 |
fft一本で逆変換(ifft)も可能だが、ビット反転位置のデータ入れ替えを省略するため、fft,ifftを使っている。
bitrv は、調査以外では使わないのでまともに動くかちと不安。
ri_carry と ri_carry_r は、繰越の方向が異なるだけ。どちらを使うかは状況による。
現在、実数fftについて検証中。メモリー使用量が半分ですむならそれに越したことは無い。