・チューニング対象 fft,ifft,r_mul
・計算は、全桁 radix-1 と radix-2 の実数乗算。(単純計算で解が求まる)
実行回数
fft2回、r_mul1回、ifft1回
解
0<=k<n/2 a[k]=(k+1)*(radix-1)*(radix-2) n/2<=k<n a[k]=(n-1- k)*(radix-1)*(radix-2)
・誤差(error)は、スケーリング後解との差の絶対値
・実行時間は、fftの合計実行時間が、1秒以上になるまで繰り返し平均値。(fft1回分)
・データは、10進。radix=1000~100000 誤差 0.25 未満
No.1 チューニング前
n=67108864=1<<26 radix=1000 fft 39.964405 , r_mul 5.791993 , ifft 38.881574 , error 0.085938 |
radix=10000の場合
n=67108864=1<<26 radix=10000 fft 39.905315 , r_mul 5.775796 , ifft 38.209183 , error 8.500000 |
No.2 メモリーのリニアアクセス化
ソース
/* ===== fft ======== */
void *fft(int nx ,ad_t a[])
{
int i, j,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(j= 0 ; j < n; j += m*2) {
for(k = 0 ; k < m; k++) {
i = j + k ;
cosw = cos(r*(double)k);
sinw = sin(r*(double)k);
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, j, k, m,n;
double tmpr, tmpi, r, cosw, sinw;
n = 1<< nx ;
r = M_PI ;
for(m = 1; m < n ; m *= 2 ) {
for(j= 0 ; j < n; j += m*2) {
for(k = 0; k < m; k++) {
i = j + k ;
cosw = cos(r*(double)k);
sinw = sin(r*(double)k);
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;
}
|
No.1 n=67108864=1<<26 radix=1000 fft 39.964405 , r_mul 5.791993 , ifft 38.881574 , error 0.085938 No.2 n=67108864=1<<26 radix=1000 fft 38.348005 , r_mul 5.744716 , ifft 41.086747 , error 0.085938 |
毎回 sin,cos が呼ばれるので遅くなると思ったが、あまり変わらない。
sin,cos が思ったより速くメモリーのリニアアクセス化では改善しないと思ったが、そうでは無かった。
No.3 sin,cos テーブル化
ソース
ad_t *sc = NULL;
void *mk_sincos_table(int nx)
{
int n ,m,nn;
double r ;
if( sc != NULL ){
free(sc);
sc = NULL ;
}
if( nx <= 0 ){
return ;
}
n=1<<nx;
sc=(ad_t *)malloc(sizeof(ad_t)*(n+n/2));
r = M_PI / (double)n;
for ( m=0;m<n+n/2;m++){
sc[m].r = 0.0;
sc[m].i = 0.0;
}
/* r_mul 用 (nx+1) 0 ~ pai/2 */
for ( m=0;m<=n/4;m++){
sc[n+m].r = cos(r*(double)m);
sc[n+m].i = sin(r*(double)m);
}
for ( m=1;m<n/4;m++){
sc[n+n/2-m].r = sc[n+m].i;
sc[n+n/2-m].i = sc[n+m].r;
}
/* fft,ifft,r_mul (nx) 0 ~ pai */
for (m=0 ;m<n/4;m++){
sc[n/2+m].r = sc[n+m*2].r;
sc[n/2+m].i = sc[n+m*2].i;
}
sc[n/2+n/4].r = 0.0;
sc[n/2+n/4].i = 1.0;
for (m=1 ;m<n/4;m++){
sc[n-m].r = -sc[n/2+m].r;
sc[n-m].i = sc[n/2+m].i;
}
for( nn=n/4 ; nn > 0 ; nn/=2 ){
for (m=0 ;m<nn;m++){
sc[nn+m] = sc[nn*2+m*2];
}
}
}
/* ===== fft ======== */
void *fft(int nx ,ad_t a[])
{
int i, j,k, m, n;
double tmpr, tmpi, cosw, sinw;
n = 1<<nx;
for(m = n/2; m > 0 ; m /= 2 ) {
for(j= 0 ; j < n; j += m*2) {
for(k = 0 ; k < m; k++) {
i = j + k ;
cosw = sc[m+k].r;
sinw =-sc[m+k].i;
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;
#ifdef FFT_INDEX_CHECK
if(i < 0 ) { printf("fft index under i\n"); exit ;};
if(m+i >=n ) { printf("fft index over m+i\n"); exit ;};
#endif
}
}
}
return;
}
/* ===== ifft ======== */
void *ifft(int nx,ad_t a[])
{
int i, j, k, m,n;
double tmpr, tmpi, cosw, sinw;
n = 1<< nx ;
for(m = 1; m < n ; m *= 2 ) {
for(j= 0 ; j < n; j += m*2) {
for(k = 0; k < m; k++) {
i = j + k ;
cosw = sc[m+k].r;
sinw = sc[m+k].i;
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;
#ifdef FFT_INDEX_CHECK
if(i < 0 ) { printf("ifft index under i\n"); exit ;};
if(m+i >=n ) { printf("ifft index over m+i\n"); exit ;};
#endif
}
}
}
return;
}
/* 実数fft後処理+乗算+実数ifft前処理 */
/* c = a * b ; a=b=c OK */
void *r_mul( int nx,ad_t c[],ad_t a[],ad_t b[] )
{
double wr,wi,tmpr,tmpi,r;
ad_t anr,amr,bnr,bmr;
int m,n,mr,nr ;
n = 1<< nx ;
anr.r = a[0].r + a[0].i ;
anr.i = a[0].r - a[0].i ;
anr.r *= b[0].r + b[0].i ;
anr.i *= b[0].r - b[0].i ;
c[0].r = (anr.r + anr.i)*0.5 ;
c[0].i = (anr.r - anr.i)*0.5 ;
anr = a[1];
bnr = b[1];
c[1].r = anr.r * bnr.r - anr.i * bnr.i ;
c[1].i = anr.r * bnr.i + anr.i * bnr.r ;
r = M_PI /(double)n;
mr = n - 1 ;
nr = 0 ;
for( m = 1 ; m < n/2 ; m++ ) {
nr = inc_rvbit(nx,nr);
anr = a[nr];
amr = a[mr];
bnr = b[nr];
bmr = b[mr];
/*
* wi = cos(r*(double)m)*0.5;
* wr = sin(r*(double)m)*0.5+0.5;
*/
wi = sc[n+m].r*0.5;
wr = sc[n+m].i*0.5+0.5;
/* fft 後処理 a */
tmpr = wr * (anr.r - amr.r) - wi * (anr.i + amr.i);
tmpi = wr * (anr.i + amr.i) + wi * (anr.r - amr.r);
anr.r = anr.r - tmpr ;
anr.i = anr.i - tmpi;
amr.r = amr.r + tmpr ;
amr.i = amr.i - tmpi;
/* fft 後処理 b */
tmpr = wr * (bnr.r - bmr.r) - wi * (bnr.i + bmr.i);
tmpi = wr * (bnr.i + bmr.i) + wi * (bnr.r - bmr.r);
bnr.r = bnr.r - tmpr ;
bnr.i = bnr.i - tmpi;
bmr.r = bmr.r + tmpr ;
bmr.i = bmr.i - tmpi;
/* 乗算 */
tmpr = anr.r ;
anr.r = tmpr * bnr.r - anr.i * bnr.i ;
anr.i = tmpr * bnr.i + anr.i * bnr.r ;
tmpr = amr.r ;
amr.r = tmpr * bmr.r - amr.i * bmr.i ;
amr.i = tmpr * bmr.i + amr.i * bmr.r ;
/* ifft 前処理 */
tmpr = wr * (anr.r - amr.r) + wi * (anr.i + amr.i);
tmpi = wr * (anr.i + amr.i) - wi * (anr.r - amr.r);
c[nr].r = anr.r - tmpr ;
c[nr].i = anr.i - tmpi;
c[mr].r = amr.r + tmpr ;
c[mr].i = amr.i - tmpi;
mr = n -1 - nr ;
}
}
|
fft 用として nx までの全パターン r_mul の nx (fftのnx+1に相当)を作成。
sin,cosは、0~π/4 で計算し π/4~π はそのコピー。若干精度が上がる。
(πが2のべき乗で割り切れ無いことによる誤差らしい。)
現状fft,ifftにで手を入れたく無いので0~πまで求めている。最終的には、0~π/2か0~π/4にする予定。
結果
No.1 n=67108864=1<<26 radix=1000 fft 39.964405 , r_mul 5.791993 , ifft 38.881574 , error 0.085938 No.2 n=67108864=1<<26 radix=1000 fft 38.348005 , r_mul 5.744716 , ifft 41.086747 , error 0.085938 No.3 n=67108864=1<<26 radix=1000 fft 3.771606 , r_mul 4.460116 , ifft 4.872133 , error 0.046875 |
fftとifftの差は、バグでは無く設定データ(全桁同一)によるものらしい。
r_mulが、1LOOPなのにfft,ifftとほぼ同じなのは頂けない。
0 件のコメント:
コメントを投稿