ref: 2183f9eaeca9fb5d57b637c15707e663caf33575
dir: /appl/math/ffts.b/
implement FFTs;
include "sys.m";
sys: Sys;
print: import sys;
include "math.m";
math: Math;
cos, sin, Degree, Pi: import math;
include "ffts.m";
# by r. c. singleton, stanford research institute, sept. 1968
# translated to limbo by eric grosse, jan 1997
# arrays at(maxf), ck(maxf), bt(maxf), sk(maxf), and np(maxp)
# are used for temporary storage. if the available storage
# is insufficient, the program exits.
# maxf must be >= the maximum prime factor of n.
# maxp must be > the number of prime factors of n.
# in addition, if the square-free portion k of n has two or
# more prime factors, then maxp must be >= k-1.
# array storage in nfac for a maximum of 15 prime factors of n.
# if n has more than one square-free factor, the product of the
# square-free factors must be <= 210
ffts(a,b:array of real, ntot,n,nspan,isn:int){
maxp: con 209;
i,ii,inc,j,jc,jf,jj,k,k1,k2,k3,k4,kk:int;
ks,kspan,kspnn,kt,m,maxf,nn,nt:int;
aa,aj,ajm,ajp,ak,akm,akp,bb,bj,bjm,bjp,bk,bkm,bkp:real;
c1,c2,c3,c72,cd,rad,radf,s1,s2,s3,s72,s120,sd:real;
maxf = 23;
if(math == nil){
sys = load Sys Sys->PATH;
math = load Math Math->PATH;
}
nfac := array[12] of int;
np := array[maxp] of int;
at := array[23] of real;
ck := array[23] of real;
bt := array[23] of real;
sk := array[23] of real;
if(n<2) return;
inc = isn;
c72 = cos(72.*Degree);
s72 = sin(72.*Degree);
s120 = sin(120.*Degree);
rad = 2.*Pi;
if(isn<0){
s72 = -s72;
s120 = -s120;
rad = -rad;
inc = -inc;
}
nt = inc*ntot;
ks = inc*nspan;
kspan = ks;
nn = nt-inc;
jc = ks/n;
radf = rad*real(jc)*0.5;
i = 0;
jf = 0;
# determine the factors of n
m = 0;
k = n;
while(k==k/16*16){
m = m+1;
nfac[m] = 4;
k = k/16;
}
j = 3;
jj = 9;
for(;;)
if(k%jj==0){
m = m+1;
nfac[m] = j;
k = k/jj;
}else{
j = j+2;
jj = j*j;
if(jj>k)
break;
}
if(k<=4){
kt = m;
nfac[m+1] = k;
if(k!=1)
m = m+1;
}else{
if(k==k/4*4){
m = m+1;
nfac[m] = 2;
k = k/4;
}
kt = m;
j = 2;
do{
if(k%j==0){
m = m+1;
nfac[m] = j;
k = k/j;
}
j = ((j+1)/2)*2+1;
}while(j<=k);
}
if(kt!=0){
j = kt;
do{
m = m+1;
nfac[m] = nfac[j];
j = j-1;
}while(j!=0);
}
for(;;){ # compute fourier transform
sd = radf/real(kspan);
cd = sin(sd);
cd = 2.0*cd*cd;
sd = sin(sd+sd);
kk = 1;
i = i+1;
if(nfac[i]==2){ # transform for factor of 2 (including rotation factor)
kspan = kspan/2;
k1 = kspan+2;
for(;;){
k2 = kk+kspan;
ak = a[k2-1];
bk = b[k2-1];
a[k2-1] = a[kk-1]-ak;
b[k2-1] = b[kk-1]-bk;
a[kk-1] = a[kk-1]+ak;
b[kk-1] = b[kk-1]+bk;
kk = k2+kspan;
if(kk>nn){
kk = kk-nn;
if(kk>jc)
break;
}
}
if(kk>kspan)
break;
do{
c1 = 1.0-cd;
s1 = sd;
for(;;){
k2 = kk+kspan;
ak = a[kk-1]-a[k2-1];
bk = b[kk-1]-b[k2-1];
a[kk-1] = a[kk-1]+a[k2-1];
b[kk-1] = b[kk-1]+b[k2-1];
a[k2-1] = c1*ak-s1*bk;
b[k2-1] = s1*ak+c1*bk;
kk = k2+kspan;
if(kk>=nt){
k2 = kk-nt;
c1 = -c1;
kk = k1-k2;
if(kk<=k2){
ak = c1-(cd*c1+sd*s1);
s1 = (sd*c1-cd*s1)+s1;
c1 = 2.0-(ak*ak+s1*s1);
s1 = c1*s1;
c1 = c1*ak;
kk = kk+jc;
if(kk>=k2)
break;
}
}
}
k1 = k1+inc+inc;
kk = (k1-kspan)/2+jc;
}while(kk<=jc+jc);
}else{ # transform for factor of 4
if(nfac[i]!=4){
# transform for odd factors
k = nfac[i];
kspnn = kspan;
kspan = kspan/k;
if(k==3)
for(;;){
# transform for factor of 3 (optional code)
k1 = kk+kspan;
k2 = k1+kspan;
ak = a[kk-1];
bk = b[kk-1];
aj = a[k1-1]+a[k2-1];
bj = b[k1-1]+b[k2-1];
a[kk-1] = ak+aj;
b[kk-1] = bk+bj;
ak = -0.5*aj+ak;
bk = -0.5*bj+bk;
aj = (a[k1-1]-a[k2-1])*s120;
bj = (b[k1-1]-b[k2-1])*s120;
a[k1-1] = ak-bj;
b[k1-1] = bk+aj;
a[k2-1] = ak+bj;
b[k2-1] = bk-aj;
kk = k2+kspan;
if(kk>=nn){
kk = kk-nn;
if(kk>kspan)
break;
}
}
else if(k==5){
# transform for factor of 5 (optional code)
c2 = c72*c72-s72*s72;
s2 = 2.0*c72*s72;
for(;;){
k1 = kk+kspan;
k2 = k1+kspan;
k3 = k2+kspan;
k4 = k3+kspan;
akp = a[k1-1]+a[k4-1];
akm = a[k1-1]-a[k4-1];
bkp = b[k1-1]+b[k4-1];
bkm = b[k1-1]-b[k4-1];
ajp = a[k2-1]+a[k3-1];
ajm = a[k2-1]-a[k3-1];
bjp = b[k2-1]+b[k3-1];
bjm = b[k2-1]-b[k3-1];
aa = a[kk-1];
bb = b[kk-1];
a[kk-1] = aa+akp+ajp;
b[kk-1] = bb+bkp+bjp;
ak = akp*c72+ajp*c2+aa;
bk = bkp*c72+bjp*c2+bb;
aj = akm*s72+ajm*s2;
bj = bkm*s72+bjm*s2;
a[k1-1] = ak-bj;
a[k4-1] = ak+bj;
b[k1-1] = bk+aj;
b[k4-1] = bk-aj;
ak = akp*c2+ajp*c72+aa;
bk = bkp*c2+bjp*c72+bb;
aj = akm*s2-ajm*s72;
bj = bkm*s2-bjm*s72;
a[k2-1] = ak-bj;
a[k3-1] = ak+bj;
b[k2-1] = bk+aj;
b[k3-1] = bk-aj;
kk = k4+kspan;
if(kk>=nn){
kk = kk-nn;
if(kk>kspan)
break;
}
}
}else{
if(k!=jf){
jf = k;
s1 = rad/real(k);
c1 = cos(s1);
s1 = sin(s1);
if(jf>maxf){
sys->fprint(sys->fildes(2),"too many primes for fft");
exit;
}
ck[jf-1] = 1.0;
sk[jf-1] = 0.0;
j = 1;
do{
ck[j-1] = ck[k-1]*c1+sk[k-1]*s1;
sk[j-1] = ck[k-1]*s1-sk[k-1]*c1;
k = k-1;
ck[k-1] = ck[j-1];
sk[k-1] = -sk[j-1];
j = j+1;
}while(j<k);
}
for(;;){
k1 = kk;
k2 = kk+kspnn;
aa = a[kk-1];
bb = b[kk-1];
ak = aa;
bk = bb;
j = 1;
k1 = k1+kspan;
do{
k2 = k2-kspan;
j = j+1;
at[j-1] = a[k1-1]+a[k2-1];
ak = at[j-1]+ak;
bt[j-1] = b[k1-1]+b[k2-1];
bk = bt[j-1]+bk;
j = j+1;
at[j-1] = a[k1-1]-a[k2-1];
bt[j-1] = b[k1-1]-b[k2-1];
k1 = k1+kspan;
}while(k1<k2);
a[kk-1] = ak;
b[kk-1] = bk;
k1 = kk;
k2 = kk+kspnn;
j = 1;
do{
k1 = k1+kspan;
k2 = k2-kspan;
jj = j;
ak = aa;
bk = bb;
aj = 0.0;
bj = 0.0;
k = 1;
do{
k = k+1;
ak = at[k-1]*ck[jj-1]+ak;
bk = bt[k-1]*ck[jj-1]+bk;
k = k+1;
aj = at[k-1]*sk[jj-1]+aj;
bj = bt[k-1]*sk[jj-1]+bj;
jj = jj+j;
if(jj>jf)
jj = jj-jf;
}while(k<jf);
k = jf-j;
a[k1-1] = ak-bj;
b[k1-1] = bk+aj;
a[k2-1] = ak+bj;
b[k2-1] = bk-aj;
j = j+1;
}while(j<k);
kk = kk+kspnn;
if(kk>nn){
kk = kk-nn;
if(kk>kspan)
break;
}
}
}
# multiply by rotation factor (except for factors of 2 and 4)
if(i==m)
break;
kk = jc+1;
do{
c2 = 1.0-cd;
s1 = sd;
do{
c1 = c2;
s2 = s1;
kk = kk+kspan;
for(;;){
ak = a[kk-1];
a[kk-1] = c2*ak-s2*b[kk-1];
b[kk-1] = s2*ak+c2*b[kk-1];
kk = kk+kspnn;
if(kk>nt){
ak = s1*s2;
s2 = s1*c2+c1*s2;
c2 = c1*c2-ak;
kk = kk-nt+kspan;
if(kk>kspnn)
break;
}
}
c2 = c1-(cd*c1+sd*s1);
s1 = s1+(sd*c1-cd*s1);
c1 = 2.0-(c2*c2+s1*s1);
s1 = c1*s1;
c2 = c1*c2;
kk = kk-kspnn+jc;
}while(kk<=kspan);
kk = kk-kspan+jc+inc;
}while(kk<=jc+jc);
}else{
kspnn = kspan;
kspan = kspan/4;
do{
c1 = 1.;
s1 = 0.;
for(;;){
k1 = kk+kspan;
k2 = k1+kspan;
k3 = k2+kspan;
akp = a[kk-1]+a[k2-1];
akm = a[kk-1]-a[k2-1];
ajp = a[k1-1]+a[k3-1];
ajm = a[k1-1]-a[k3-1];
a[kk-1] = akp+ajp;
ajp = akp-ajp;
bkp = b[kk-1]+b[k2-1];
bkm = b[kk-1]-b[k2-1];
bjp = b[k1-1]+b[k3-1];
bjm = b[k1-1]-b[k3-1];
b[kk-1] = bkp+bjp;
bjp = bkp-bjp;
do10 := 0;
if(isn<0){
akp = akm+bjm;
akm = akm-bjm;
bkp = bkm-ajm;
bkm = bkm+ajm;
if(s1!=0.) do10 = 1;
}else{
akp = akm-bjm;
akm = akm+bjm;
bkp = bkm+ajm;
bkm = bkm-ajm;
if(s1!=0.) do10 = 1;
}
if(do10){
a[k1-1] = akp*c1-bkp*s1;
b[k1-1] = akp*s1+bkp*c1;
a[k2-1] = ajp*c2-bjp*s2;
b[k2-1] = ajp*s2+bjp*c2;
a[k3-1] = akm*c3-bkm*s3;
b[k3-1] = akm*s3+bkm*c3;
kk = k3+kspan;
if(kk<=nt)
continue;
}else{
a[k1-1] = akp;
b[k1-1] = bkp;
a[k2-1] = ajp;
b[k2-1] = bjp;
a[k3-1] = akm;
b[k3-1] = bkm;
kk = k3+kspan;
if(kk<=nt)
continue;
}
c2 = c1-(cd*c1+sd*s1);
s1 = (sd*c1-cd*s1)+s1;
c1 = 2.0-(c2*c2+s1*s1);
s1 = c1*s1;
c1 = c1*c2;
c2 = c1*c1-s1*s1;
s2 = 2.0*c1*s1;
c3 = c2*c1-s2*s1;
s3 = c2*s1+s2*c1;
kk = kk-nt+jc;
if(kk>kspan)
break;
}
kk = kk-kspan+inc;
}while(kk<=jc);
if(kspan==jc)
break;
}
}
} # end "compute fourier transform"
# permute the results to normal order---done in two stages
# permutation for square factors of n
np[0] = ks;
if(kt!=0){
k = kt+kt+1;
if(m<k)
k = k-1;
j = 1;
np[k] = jc;
do{
np[j] = np[j-1]/nfac[j];
np[k-1] = np[k]*nfac[j];
j = j+1;
k = k-1;
}while(j<k);
k3 = np[k];
kspan = np[1];
kk = jc+1;
k2 = kspan+1;
j = 1;
if(n!=ntot){
for(;;){
# permutation for multivariate transform
k = kk+jc;
do{
ak = a[kk-1];
a[kk-1] = a[k2-1];
a[k2-1] = ak;
bk = b[kk-1];
b[kk-1] = b[k2-1];
b[k2-1] = bk;
kk = kk+inc;
k2 = k2+inc;
}while(kk<k);
kk = kk+ks-jc;
k2 = k2+ks-jc;
if(kk>=nt){
k2 = k2-nt+kspan;
kk = kk-nt+jc;
if(k2>=ks)
permm: for(;;){
k2 = k2-np[j-1];
j = j+1;
k2 = np[j]+k2;
if(k2<=np[j-1]){
j = 1;
do{
if(kk<k2)
break permm;
kk = kk+jc;
k2 = kspan+k2;
}while(k2<ks);
if(kk>=ks)
break permm;
}
}
}
}
jc = k3;
}else{
for(;;){
# permutation for single-variate transform (optional code)
ak = a[kk-1];
a[kk-1] = a[k2-1];
a[k2-1] = ak;
bk = b[kk-1];
b[kk-1] = b[k2-1];
b[k2-1] = bk;
kk = kk+inc;
k2 = kspan+k2;
if(k2>=ks)
perms: for(;;){
k2 = k2-np[j-1];
j = j+1;
k2 = np[j]+k2;
if(k2<=np[j-1]){
j = 1;
do{
if(kk<k2)
break perms;
kk = kk+inc;
k2 = kspan+k2;
}while(k2<ks);
if(kk>=ks)
break perms;
}
}
}
jc = k3;
}
}
if(2*kt+1>=m)
return;
kspnn = np[kt];
# permutation for square-free factors of n
j = m-kt;
nfac[j+1] = 1;
do{
nfac[j] = nfac[j]*nfac[j+1];
j = j-1;
}while(j!=kt);
kt = kt+1;
nn = nfac[kt]-1;
if(nn<=maxp){
jj = 0;
j = 0;
for(;;){
k2 = nfac[kt];
k = kt+1;
kk = nfac[k];
j = j+1;
if(j>nn)
break;
for(;;){
jj = kk+jj;
if(jj<k2)
break;
jj = jj-k2;
k2 = kk;
k = k+1;
kk = nfac[k];
}
np[j-1] = jj;
}
# determine the permutation cycles of length greater than 1
j = 0;
for(;;){
j = j+1;
kk = np[j-1];
if(kk>=0)
if(kk==j){
np[j-1] = -j;
if(j==nn)
break;
}else{
do{
k = kk;
kk = np[k-1];
np[k-1] = -kk;
}while(kk!=j);
k3 = kk;
}
}
maxf = inc*maxf;
for(;;){
j = k3+1;
nt = nt-kspnn;
ii = nt-inc+1;
if(nt<0)
break;
for(;;){
j = j-1;
if(np[j-1]>=0){
jj = jc;
do{
kspan = jj;
if(jj>maxf)
kspan = maxf;
jj = jj-kspan;
k = np[j-1];
kk = jc*k+ii+jj;
k1 = kk+kspan;
k2 = 0;
do{
k2 = k2+1;
at[k2-1] = a[k1-1];
bt[k2-1] = b[k1-1];
k1 = k1-inc;
}while(k1!=kk);
do{
k1 = kk+kspan;
k2 = k1-jc*(k+np[k-1]);
k = -np[k-1];
do{
a[k1-1] = a[k2-1];
b[k1-1] = b[k2-1];
k1 = k1-inc;
k2 = k2-inc;
}while(k1!=kk);
kk = k2;
}while(k!=j);
k1 = kk+kspan;
k2 = 0;
do{
k2 = k2+1;
a[k1-1] = at[k2-1];
b[k1-1] = bt[k2-1];
k1 = k1-inc;
}while(k1!=kk);
}while(jj!=0);
if(j==1)
break;
}
}
}
}
}