/************************************************************************* 1-dimensional Fast Hartley Transform. Algorithm has O(N*logN) complexity for any N (composite or prime). INPUT PARAMETERS A - array[0..N-1] - real function to be transformed N - problem size OUTPUT PARAMETERS A - FHT of a input array, array[0..N-1], A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1) -- ALGLIB -- Copyright 04.06.2009 by Bochkanov Sergey *************************************************************************/ void fhtr1d(ap::real_1d_array& a, int n) { ftplan plan; int i; ap::complex_1d_array fa; ap::ap_error::make_assertion(n>0, "FHTR1D: incorrect N!"); // // Special case: N=1, FHT is just identity transform. // After this block we assume that N is strictly greater than 1. // if( n==1 ) { return; } // // Reduce FHt to real FFT // fftr1d(a, n, fa); for(i = 0; i <= n-1; i++) { a(i) = fa(i).x-fa(i).y; } }
/************************************************************************* Test *************************************************************************/ bool testfft(bool silent) { bool result; int n; int i; int k; ap::complex_1d_array a1; ap::complex_1d_array a2; ap::complex_1d_array a3; ap::real_1d_array r1; ap::real_1d_array r2; ap::real_1d_array buf; ftplan plan; int maxn; double bidierr; double bidirerr; double referr; double refrerr; double reinterr; double errtol; bool referrors; bool bidierrors; bool refrerrors; bool bidirerrors; bool reinterrors; bool waserrors; maxn = 128; errtol = 100*pow(double(maxn), double(3)/double(2))*ap::machineepsilon; bidierrors = false; referrors = false; bidirerrors = false; refrerrors = false; reinterrors = false; waserrors = false; // // Test bi-directional error: norm(x-invFFT(FFT(x))) // bidierr = 0; bidirerr = 0; for(n = 1; n <= maxn; n++) { // // Complex FFT/invFFT // a1.setlength(n); a2.setlength(n); a3.setlength(n); for(i = 0; i <= n-1; i++) { a1(i).x = 2*ap::randomreal()-1; a1(i).y = 2*ap::randomreal()-1; a2(i) = a1(i); a3(i) = a1(i); } fftc1d(a2, n); fftc1dinv(a2, n); fftc1dinv(a3, n); fftc1d(a3, n); for(i = 0; i <= n-1; i++) { bidierr = ap::maxreal(bidierr, ap::abscomplex(a1(i)-a2(i))); bidierr = ap::maxreal(bidierr, ap::abscomplex(a1(i)-a3(i))); } // // Real // r1.setlength(n); r2.setlength(n); for(i = 0; i <= n-1; i++) { r1(i) = 2*ap::randomreal()-1; r2(i) = r1(i); } fftr1d(r2, n, a1); ap::vmul(&r2(0), ap::vlen(0,n-1), 0); fftr1dinv(a1, n, r2); for(i = 0; i <= n-1; i++) { bidirerr = ap::maxreal(bidirerr, ap::abscomplex(r1(i)-r2(i))); } } bidierrors = bidierrors||bidierr>errtol; bidirerrors = bidirerrors||bidirerr>errtol; // // Test against reference O(N^2) implementation // referr = 0; refrerr = 0; for(n = 1; n <= maxn; n++) { // // Complex FFT // a1.setlength(n); a2.setlength(n); for(i = 0; i <= n-1; i++) { a1(i).x = 2*ap::randomreal()-1; a1(i).y = 2*ap::randomreal()-1; a2(i) = a1(i); } fftc1d(a1, n); reffftc1d(a2, n); for(i = 0; i <= n-1; i++) { referr = ap::maxreal(referr, ap::abscomplex(a1(i)-a2(i))); } // // Complex inverse FFT // a1.setlength(n); a2.setlength(n); for(i = 0; i <= n-1; i++) { a1(i).x = 2*ap::randomreal()-1; a1(i).y = 2*ap::randomreal()-1; a2(i) = a1(i); } fftc1dinv(a1, n); reffftc1dinv(a2, n); for(i = 0; i <= n-1; i++) { referr = ap::maxreal(referr, ap::abscomplex(a1(i)-a2(i))); } // // Real forward/inverse FFT: // * calculate and check forward FFT // * use precalculated FFT to check backward FFT // fill unused parts of frequencies array with random numbers // to ensure that they are not really used // r1.setlength(n); r2.setlength(n); for(i = 0; i <= n-1; i++) { r1(i) = 2*ap::randomreal()-1; r2(i) = r1(i); } fftr1d(r1, n, a1); refinternalrfft(r2, n, a2); for(i = 0; i <= n-1; i++) { refrerr = ap::maxreal(refrerr, ap::abscomplex(a1(i)-a2(i))); } a3.setlength(ap::ifloor(double(n)/double(2))+1); for(i = 0; i <= ap::ifloor(double(n)/double(2)); i++) { a3(i) = a2(i); } a3(0).y = 2*ap::randomreal()-1; if( n%2==0 ) { a3(ap::ifloor(double(n)/double(2))).y = 2*ap::randomreal()-1; } for(i = 0; i <= n-1; i++) { r1(i) = 0; } fftr1dinv(a3, n, r1); for(i = 0; i <= n-1; i++) { refrerr = ap::maxreal(refrerr, fabs(r2(i)-r1(i))); } } referrors = referrors||referr>errtol; refrerrors = refrerrors||refrerr>errtol; // // test internal real even FFT // reinterr = 0; for(k = 1; k <= maxn/2; k++) { n = 2*k; // // Real forward FFT // r1.setlength(n); r2.setlength(n); for(i = 0; i <= n-1; i++) { r1(i) = 2*ap::randomreal()-1; r2(i) = r1(i); } ftbasegeneratecomplexfftplan(n/2, plan); buf.setlength(n); fftr1dinternaleven(r1, n, buf, plan); refinternalrfft(r2, n, a2); reinterr = ap::maxreal(reinterr, fabs(r1(0)-a2(0).x)); reinterr = ap::maxreal(reinterr, fabs(r1(1)-a2(n/2).x)); for(i = 1; i <= n/2-1; i++) { reinterr = ap::maxreal(reinterr, fabs(r1(2*i+0)-a2(i).x)); reinterr = ap::maxreal(reinterr, fabs(r1(2*i+1)-a2(i).y)); } // // Real backward FFT // r1.setlength(n); for(i = 0; i <= n-1; i++) { r1(i) = 2*ap::randomreal()-1; } a2.setlength(ap::ifloor(double(n)/double(2))+1); a2(0) = r1(0); for(i = 1; i <= ap::ifloor(double(n)/double(2))-1; i++) { a2(i).x = r1(2*i+0); a2(i).y = r1(2*i+1); } a2(ap::ifloor(double(n)/double(2))) = r1(1); ftbasegeneratecomplexfftplan(n/2, plan); buf.setlength(n); fftr1dinvinternaleven(r1, n, buf, plan); fftr1dinv(a2, n, r2); for(i = 0; i <= n-1; i++) { reinterr = ap::maxreal(reinterr, fabs(r1(i)-r2(i))); } } reinterrors = reinterrors||reinterr>errtol; // // end // waserrors = bidierrors||bidirerrors||referrors||refrerrors||reinterrors; if( !silent ) { printf("TESTING FFT\n"); printf("FINAL RESULT: "); if( waserrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* BI-DIRECTIONAL COMPLEX TEST: "); if( bidierrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* AGAINST REFERENCE COMPLEX FFT: "); if( referrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* BI-DIRECTIONAL REAL TEST: "); if( bidirerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* AGAINST REFERENCE REAL FFT: "); if( refrerrors ) { printf("FAILED\n"); } else { printf("OK\n"); } printf("* INTERNAL EVEN FFT: "); if( reinterrors ) { printf("FAILED\n"); } else { printf("OK\n"); } if( waserrors ) { printf("TEST FAILED\n"); } else { printf("TEST PASSED\n"); } } result = !waserrors; return result; }