任意长度FFT算法的C++实现

头文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                                fftpf.h
 *
 * Fast Fourier Transform with prime factor algorithm
 *
 * This class is designed for calculating discrete Fourier transform and
 * inverse discrete Fourier transform of 1D signals by using prime factor
 * algorithms. The signals can be arbitrary length. The largest prime factor
 * of n must be less than or equal to the constant PRIMEFACTOR defined below.
 *
 * The general idea is to factor the length of the DFT "n" into factors that are
 * efficiently handled by the routines. A number of short DFT's are implemented
 * with a minimum of arithmetical operations and using(almost) straight line
 * code resultingin very fast execution when the factors of n belong to this
 * set. Especially radix-10 is optimized. Prime factors, that are not in the
 * set of short DFT's are handled with direct evaluation of the DFP expression.
 *
 * The algorithm is modified from "xFFT.h" of "Pratical Fourier Transform
 * and C++ Implementation" written by Hequan Sun.
 *
 * Zhang Ming, 2010-09, Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef FFTPF_H
#define FFTPF_H


#include <vector.h>

#define     PRIMEFACTOR     37
#define     PRIMEFACTORHALF (PRIMEFACTOR+1)/2
#define     PRIMECOUNT      20


namespace splab
{

    template<class Type>
    class FFTPF
    {

    public:

        FFTPF();
        ~FFTPF();

        void    fft( const Vector<Type> &xn, Vector< complex<Type> > &Xk );
        void    ifft( const Vector< complex<Type> > &Xk, Vector<Type> &xn );

        void    fft( const Vector< complex<Type> > &xn,
                     Vector< complex<Type> > &Xk );
        void    ifft( const Vector< complex<Type> > &Xk,
                      Vector< complex<Type> > &xn );

    private:

        bool    bAlloc;
        int     mNOldSize, mNFactor, nNewFactorSize, nHalfFactorSize,
                groupOffset, dataOffset, blockOffset, adr, groupNo,
                dataNo, blockNo, twNo;
        int     mSofarRadix[PRIMECOUNT], mActualRadix[PRIMECOUNT],
                mRemainRadix[PRIMECOUNT];

        Type    tPI, t2PI, tIRT2, tIRT3, omega, twRe, twIim;
        Type    *pftwRe, *pftgRe, *pfzRe, *pfvRe, *pfwRe, *pftwIm, *pftgIm,
                *pfzIm, *pfvIm, *pfwIm;
        Type    twiddleRe[PRIMEFACTOR], trigRe[PRIMEFACTOR],  zRe[PRIMEFACTOR],
                twiddleIm[PRIMEFACTOR], trigIm[PRIMEFACTOR],  zIm[PRIMEFACTOR],
                vRe[PRIMEFACTORHALF],   wRe[PRIMEFACTORHALF],
                vIm[PRIMEFACTORHALF],   wIm[PRIMEFACTORHALF];

        Type    c3_1,
                c5_1,  c5_2,   c5_3,  c5_4,   c5_5,
                c7_1,  c7_2,   c7_3,  c7_4,   c7_5,   c7_6,
                c9_2,  c9_3,   c9_4,  c9_5,   c9_6,   c9_7,   c9_8,  c9_9,
                c11_1, c11_2,  c11_3, c11_4,  c11_5,  c11_6,  c11_7, c11_8,
                c11_9, c11_10, c13_1, c13_2,  c13_3,  c13_4,  c13_5, c13_6,
                c13_7, c13_8,  c13_9, c13_10, c13_11, c13_12, c16_2, c16_3,
                c16_4, c16_5;

        Type    ttmp,
                t1_re,  t1_im,  t2_re,  t2_im,  t3_re,  t3_im,  t4_re,  t4_im,
                t5_re,  t5_im,  t6_re,  t6_im,  t7_re,  t7_im,  t8_re,  t8_im,
                t9_re,  t9_im,  t10_re, t10_im, t11_re, t11_im, t12_re, t12_im,
                t13_re, t13_im, t14_re, t14_im, t15_re, t15_im, t16_re, t16_im,
                t17_re, t17_im, t18_re, t18_im, t19_re, t19_im, t20_re, t20_im,
                t21_re, t21_im, t22_re, t22_im,
                m1_re,  m1_im,  m2_re,  m2_im,  m3_re,  m3_im,  m4_re,  m4_im,
                m5_re,  m5_im,  m6_re,  m6_im,  m7_re,  m7_im,  m8_re,  m8_im,
                m9_re,  m9_im,  m10_re, m10_im, m11_re, m11_im, m12_re, m12_im;

        void    releaseMem();
        void    allocateMem();
        void    factorize( int n, int &nFact, int *fact);
        void    primeSetup( int nPoints );
        void    permute( const Vector<Type> &xn, Vector< complex<Type> > &yn );
        void    permute( const Vector< complex<Type> > &xn, Vector< complex<Type> > &yn,
                         bool bTrans=true );
        void    initTrig( int radix );
        void    radix2( Type *aRe, Type *aIm );
        void    radix3( Type *aRe, Type *aIm );
        void    radix4( Type *aRe, Type *aIm );
        void    radix5( Type *aRe, Type *aIm );
        void    radix7( Type *aRe, Type *aIm );
        void    radix8( Type *aRe, Type *aIm );
        void    radix9( Type *aRe, Type *aIm );
        void    radix10( Type *aRe, Type *aIm );
        void    radix11( Type *aRe, Type *aIm );
        void    radix13( Type *aRe, Type *aIm );
        void    radix16( Type *aRe, Type *aIm );
        void    radixOther( int radix );
        void    twiddleFFT( int sofarRadix, int radix, int remainRadix,
                            Vector< complex<Type> > &yn );

    };
    // class FFTPF


    #include <fftpf-impl.h>

}
// namespace splab


#endif
//FFTPF_H

实现文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                               fftpf-impl.h
 *
 * Implementation for FFTPF class.
 *
 * Zhang Ming, 2010-09, Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * constructors and destructor
 */
template<class Type>
FFTPF<Type>::FFTPF()
{
    bAlloc = false;
    mNOldSize = nNewFactorSize = nHalfFactorSize = 0;

    pftwRe = twiddleRe;
    pftwIm = twiddleIm;
	pftgRe = trigRe;
	pftgIm = trigIm;
	pfzRe = zRe;
	pfzIm = zIm;
	pfvRe = vRe;
	pfvIm = vIm;
	pfwRe = wRe;
	pfwIm = wIm;

	tIRT2 = Type(sqrt(2.0)/2);
	tIRT3 = Type(sqrt(3.0)/2);
	tPI   = Type(4*atan(1.0));
	t2PI  = 2*tPI;
	Type tphi = t2PI/5;

	c3_1 = -1.5;
	c5_1 = Type((cos(tphi)-cos(2*tphi))/2);
	c5_2 = Type(sin(tphi));
	c5_3 = Type(sin(2*tphi));
	c5_4 = Type((c5_3+c5_2));
	c5_3 = c5_2-c5_3;
	c5_5 = 1.25;

	tphi = t2PI/7;
	c7_1 = Type(cos(tphi));
	c7_2 = Type(cos(2*tphi));
	c7_3 = Type(cos(3*tphi));
	c7_4 = Type(sin(tphi));
	c7_5 = Type(sin(2*tphi));
	c7_6 = Type(sin(3*tphi));

	tphi = t2PI/9;
	c9_4 = Type(cos(tphi));
	c9_8 = Type(sin(8*tphi));
	c9_3 = Type(cos(2*tphi));
	c9_7 = Type(sin(2*tphi));
	c9_5 = Type(cos(3*tphi));
	c9_2 = Type(cos(4*tphi));
	c9_6 = Type(sin(5*tphi));

	tphi = t2PI/11;
	c11_1 = Type(cos(tphi));
	c11_2 = Type(cos(2*tphi));
	c11_3 = Type(cos(3*tphi));
	c11_4 = Type(cos(4*tphi));
	c11_5 = Type(cos(5*tphi));
	c11_6 = Type(sin(tphi));
	c11_7 = Type(sin(2*tphi));
	c11_8 = Type(sin(3*tphi));
	c11_9 = Type(sin(4*tphi));
	c11_10 = Type(sin(5*tphi));

	tphi = t2PI/13;
	c13_1 = Type(cos(tphi));
	c13_2 = Type(cos(2*tphi));
	c13_3 = Type(cos(3*tphi));
	c13_4 = Type(cos(4*tphi));
	c13_5 = Type(cos(5*tphi));
	c13_6 = Type(cos(6*tphi));
	c13_7 = Type(sin(tphi));
	c13_8 = Type(sin(2*tphi));
	c13_9 = Type(sin(3*tphi));
	c13_10 = Type(sin(4*tphi));
	c13_11 = Type(sin(5*tphi));
	c13_12 = Type(sin(6*tphi));

	tphi = t2PI/16;
	c16_2 = Type(sin(tphi));
	c16_5 = Type(cos(tphi));
	c16_3 = c16_2+c16_5;
	c16_4 = c16_5-c16_2;
}


template<class Type>
FFTPF<Type>::~FFTPF()
{
    releaseMem();
}


template<class Type>
void FFTPF<Type>::releaseMem()
{
	if ( !bAlloc)
        return;

	if ( NULL != pftwRe )
        delete []pftwRe;
	if ( NULL != pftwIm )
        delete []pftwIm;
	if ( NULL != pftgRe )
        delete []pftgRe;
	if ( NULL != pftgIm )
        delete []pftgIm;
	if ( NULL != pfzRe )
        delete []pfzRe;
	if ( NULL != pfzIm )
        delete []pfzIm;
	if ( NULL != pfvRe )
        delete []pfvRe;
	if ( NULL != pfvIm )
        delete []pfvIm;
	if ( NULL != pfwRe )
        delete []pfwRe;
	if ( NULL != pfwIm )
        delete []pfwIm;

	bAlloc = false;
	nNewFactorSize = nHalfFactorSize = 0;
}


/**
 * allocate memory
 */
template<class Type>
inline void FFTPF<Type>::allocateMem()
{
	pftwRe = new Type[nNewFactorSize];
	pftwIm = new Type[nNewFactorSize];
	pftgRe = new Type[nNewFactorSize];
	pftgIm = new Type[nNewFactorSize];
	pfzRe  = new Type[nNewFactorSize];
	pfzIm  = new Type[nNewFactorSize];
	pfvRe  = new Type[nHalfFactorSize];
	pfvIm  = new Type[nHalfFactorSize];
	pfwRe  = new Type[nHalfFactorSize];
	pfwIm  = new Type[nHalfFactorSize];
	bAlloc = true;
}


/**
 * factoring the transformation length.
 */
template<class Type>
void FFTPF<Type>::factorize( int n, int &nFact, int *fact )
{
	int i, j=0, k,
        nRadix = 11, radices[12],
        factors[PRIMECOUNT];

	radices[1] = 2;  radices[2] = 3;   radices[3] = 4;   radices[4] = 5;
	radices[5] = 7;  radices[6] = 8;   radices[7] = 9;   radices[8] = 10;
	radices[9] = 11; radices[10] = 13; radices[11] = 16;

	if( 1 == n )
	{
	    j = 1;
	    factors[1] = 1;
    }

	i = nRadix;
	while( (n>1) && (i>0) )
	{
		if( (n%radices[i]) != 0 )
            --i;
		else
		{
		    n = n/radices[i];
		    j++;
		    factors[j] = radices[i];
        }
	}

	if( 2 == factors[j] )
	{
		i = j-1;
		while( (i>0) && (factors[i]!=8) )
            i--;
		if( i > 0 )
		{
		    factors[j] = 4;
		    factors[i] = 4;
        }
	}

	if( n > 1 )
	{
		for( k=2; k<sqrt(1.0*n)+1; ++k )
            while( 0 == (n%k) )
            {
                n = n/k;
                j++;
                factors[j] = k;
            }
		if( n > 1 )
		{
		    j++;
		    factors[j] = n;
        }
	}

	for( i=1; i<=j; ++i )
        fact[i] = factors[j-i+1];

	nFact = j;
}


/**
 * After N is factored the parameters that control the stages are generated.
 * For each stage we have:
 * mSofarRadix  : the product of the radices so far.
 * mActualRadix : the radix handled in this stage.
 * mRemainRadix : the product of the remaining radices.
 */
template<class Type>
void FFTPF<Type>::primeSetup( int nPoints )
{
	factorize( nPoints, mNFactor, mActualRadix );

	if( mActualRadix[1] > PRIMEFACTOR )
	{
		bool bdone = true;
		if( bAlloc )
		{
			if( mActualRadix[1] <= nNewFactorSize )
                bdone=false;
			else
			{
			    releaseMem();
			    bdone=true;
            }
		}

		if( bdone )
		{
			nNewFactorSize  = mActualRadix[1];
			nHalfFactorSize = (nNewFactorSize+1)/2;
			allocateMem();
		}
	}

    mSofarRadix[1]  = 1;
	mRemainRadix[0] = nPoints;
	mRemainRadix[1] = nPoints/mActualRadix[1];

	for( int i=2; i<=mNFactor; ++i )
	{
		mSofarRadix[i]  = mSofarRadix[i-1] * mActualRadix[i-1];
		mRemainRadix[i] = mRemainRadix[i-1] / mActualRadix[i];
	}

	mNOldSize = nPoints;
}


/**
 * The sequence "yn" is the permuted input sequence "xn" so that the
 * following transformations can be performed in-place,and the final
 * result is the normal order.
 */
template<class Type>
void FFTPF<Type>::permute( const Vector<Type> &xn,
                           Vector< complex<Type> > &yn )
{
	int i, j, k=0, nPoint = xn.size(),
        count[PRIMECOUNT];

	for( i=1; i<=mNFactor; ++i )
        count[i] = 0;

	for( i=0; i<=nPoint-2; ++i )
	{
        yn[i] = xn[k];
		j = 1;
		k += mRemainRadix[j];
		count[1] = count[1]+1;
		while( count[j] >= mActualRadix[j] )
		{
			count[j] = 0;
			k = k - mRemainRadix[j-1] + mRemainRadix[j+1];
			j++;
			count[j] = count[j] + 1;
		}
	}
	yn[nPoint-1] = xn[nPoint-1];
}

template<class Type>
void FFTPF<Type>::permute( const Vector< complex<Type> > &xn,
                           Vector< complex<Type> > &yn,
                           bool bTrans )
{
	int i, j, k=0, nPoint = xn.size(),
        count[PRIMECOUNT];

	for( i=1; i<=mNFactor; ++i )
        count[i] = 0;

	for( i=0; i<=nPoint-2; ++i )
	{
		yn[i] = xn[k];
		j = 1;
		k += mRemainRadix[j];
		count[1] = count[1]+1;
		while( count[j] >= mActualRadix[j] )
		{
			count[j] = 0;
			k = k - mRemainRadix[j-1] + mRemainRadix[j+1];
			j++;
			count[j] = count[j] + 1;
		}
	}
	yn[nPoint-1] = xn[nPoint-1];

	if( !bTrans )
        for( i=0; i< nPoint; ++i )
            yn[i] = conj(yn[i]);
}


/**
 * initialise sine/cosine table.
 */
template<class Type>
inline void FFTPF<Type>::initTrig( int radix )
{
	Type w, xre, xim;

	w = 2*tPI/radix;
	pftgRe[0] = 1;
	pftgIm[0] = 0;
	xre = Type(cos(w));
	xim = -Type(sin(w));
	pftgRe[1] = xre;
	pftgIm[1] = xim;

	for( int i=2; i<radix; ++i )
	{
		pftgRe[i] = xre*pftgRe[i-1] - xim*pftgIm[i-1];
		pftgIm[i] = xim*pftgRe[i-1] + xre*pftgIm[i-1];
	}
}


/**
 * length 2 DFT
 */
template<class Type>
inline void FFTPF<Type>::radix2( Type *aRe, Type *aIm )
{
	t1_re  = aRe[0];
	aRe[0] = t1_re+aRe[1];
	aRe[1] = t1_re-aRe[1];

	t1_im  = aIm[0];
	aIm[0] = t1_im+aIm[1];
	aIm[1] = t1_im-aIm[1];
}


/**
 * length 3 DFT
 */
template<class Type>
inline void FFTPF<Type>::radix3( Type *aRe, Type *aIm )
{
	t1_re  = aRe[1]+aRe[2];
	t2_re  = (aRe[2]-aRe[1])*tIRT3;
	aRe[0] = aRe[0]+t1_re;

	t1_re  = aRe[0]+t1_re*c3_1;
	t1_im  = aIm[1]+aIm[2];
	t2_im  = (aIm[2]-aIm[1])*tIRT3;
	aIm[0] = aIm[0]+t1_im;

	t1_im  = aIm[0]+t1_im*c3_1;
	aRe[1] = t1_re-t2_im;
	aRe[2] = t1_re+t2_im;
	aIm[1] = t1_im+t2_re;
	aIm[2] = t1_im-t2_re;
}


/**
 * length 4 DFT
 */
template<class Type>
inline void FFTPF<Type>::radix4( Type *aRe, Type *aIm )
{
	t1_re  = aRe[0]+aRe[2];
	m2_re  = aRe[0]-aRe[2];
	t2_re  = aRe[1]+aRe[3];
	aRe[0] = t1_re+t2_re;
	aRe[2] = t1_re-t2_re;

	t1_re  = aIm[0]+aIm[2];
	m2_im  = aIm[0]-aIm[2];
	t2_re  = aIm[1]+aIm[3];
	aIm[0] = t1_re+t2_re;
	aIm[2] = t1_re-t2_re;

	t1_re = aRe[1]-aRe[3];
	t2_re = aIm[1]-aIm[3];
	aRe[1] = m2_re+t2_re;
	aRe[3] = m2_re-t2_re;
	aIm[1] = m2_im-t1_re;
	aIm[3] = m2_im+t1_re;
}


/**
 * length 5 DFT
 */
template<class Type>
inline void FFTPF<Type>::radix5( Type *aRe, Type *aIm )
{
	t1_re = aRe[1]+aRe[4];
	t2_re = aRe[2]-aRe[3];
	t3_re = aRe[1]-aRe[4];
	t4_re = aRe[2]+aRe[3];
	t5_re = (t1_re-t4_re)*c5_1;
	t1_re = t1_re+t4_re;

	aRe[0] = aRe[0]+t1_re;

	t1_re = aRe[0]-t1_re*c5_5;
	t4_re = t1_re-t5_re;
	t1_re = t1_re+t5_re;
	t5_re = (t3_re+t2_re)*c5_2;
	t3_re = t5_re-t3_re*c5_4;
	t2_re = t5_re-t2_re*c5_3;
	t1_im = aIm[1]+aIm[4];
    t2_im = aIm[2]-aIm[3];
	t3_im = aIm[1]-aIm[4];
	t4_im = aIm[2]+aIm[3];
	t5_re = (t1_im-t4_im)*c5_1; t1_im = t1_im+t4_im;

	aIm[0] = aIm[0]+t1_im;

	t1_im = aIm[0]-t1_im*c5_5;
	t4_im = t1_im-t5_re;
	t1_im = t1_im+t5_re;
	t5_re = (t3_im+t2_im)*c5_2;
	t3_im = t5_re-t3_im*c5_4;
	t2_im = t5_re-t2_im*c5_3;

	aRe[1] = t1_re+t2_im;
	aIm[1] = t1_im-t2_re;
	aRe[2] = t4_re-t3_im;
	aIm[2] = t4_im+t3_re;
	aRe[3] = t4_re+t3_im;
	aIm[3] = t4_im-t3_re;
	aRe[4] = t1_re-t2_im;
	aIm[4] = t1_im+t2_re;
}


/**
 * length 7 DFT
 */
template<class Type>
inline void FFTPF<Type>::radix7( Type *aRe, Type *aIm )
{
	t1_re = aRe[1]+aRe[6];
	t1_im = aIm[1]+aIm[6];
	t2_re = aRe[2]+aRe[5];
	t2_im = aIm[2]+aIm[5];
	t3_re = aRe[3]+aRe[4];
	t3_im = aIm[3]+aIm[4];
	t4_re = aRe[6]-aRe[1];
	t4_im = aIm[6]-aIm[1];
	t5_re = aRe[5]-aRe[2];
	t5_im = aIm[5]-aIm[2];
	t6_re = aRe[4]-aRe[3];
	t6_im = aIm[4]-aIm[3];
	t7_re = aRe[0]-Type(0.5*t3_re);
	t7_im = aIm[0]-Type(0.5*t3_im);
	t8_re = t1_re-t3_re;
	t8_im = t1_im-t3_im;
	t9_re = t2_re-t3_re;
	t9_im = t2_im-t3_im;

	m1_re = t7_re+c7_1*t8_re+c7_2*t9_re;
	m1_im = t7_im+c7_1*t8_im+c7_2*t9_im;
	m2_re = t7_re+c7_2*t8_re+c7_3*t9_re;
	m2_im = t7_im+c7_2*t8_im+c7_3*t9_im;
	m3_re = t7_re+c7_3*t8_re+c7_1*t9_re;
	m3_im = t7_im+c7_3*t8_im+c7_1*t9_im;
	m4_re = c7_6*t4_re-c7_4*t5_re+c7_5*t6_re;
	m4_im = c7_6*t4_im-c7_4*t5_im+c7_5*t6_im;
	m5_re = c7_5*t4_re-c7_6*t5_re-c7_4*t6_re;
	m5_im = c7_5*t4_im-c7_6*t5_im-c7_4*t6_im;
	m6_re = c7_4*t4_re+c7_5*t5_re+c7_6*t6_re;
	m6_im = c7_4*t4_im+c7_5*t5_im+c7_6*t6_im;

	aRe[0] = aRe[0]+t1_re+t2_re+t3_re;
	aIm[0] = aIm[0]+t1_im+t2_im+t3_im;
	aRe[1] = m1_re-m6_im;
	aIm[1] = m1_im+m6_re;
	aRe[2] = m2_re-m5_im;
	aIm[2] = m2_im+m5_re;
	aRe[3] = m3_re-m4_im;
	aIm[3] = m3_im+m4_re;
	aRe[4] = m3_re+m4_im;
	aIm[4] = m3_im-m4_re;
	aRe[5] = m2_re+m5_im;
	aIm[5] = m2_im-m5_re;
	aRe[6] = m1_re+m6_im;
	aIm[6] = m1_im-m6_re;
}


/**
 * length 8 DFT
 */
template<class Type>
inline void FFTPF<Type>::radix8( Type *aRe, Type *aIm )
{
	t1_re = aRe[0]+aRe[4];
	t2_re = aRe[0]-aRe[4];
	t3_re = aRe[1]-aRe[7];
	t4_re = aRe[1]+aRe[7];
	t7_re = aRe[2]+aRe[6];
	t6_re = aRe[2]-aRe[6];
	t5_re = aRe[3]+aRe[5];
	t8_re = aRe[3]-aRe[5];
	m2_re = t1_re+t7_re;
	m2_im = t1_re-t7_re;
	m1_re = t4_re+t5_re;
	t4_re = (t4_re-t5_re)*tIRT2;

	aRe[0] = m2_re+m1_re;
	aRe[4] = m2_re-m1_re;

	m2_re = t2_re+t4_re;
	m1_re = t2_re-t4_re;
	t1_im = t3_re-t8_re;
	t3_re = (t3_re+t8_re)*tIRT2;
	t2_im = t3_re+t6_re;
	t4_im = t3_re-t6_re;
	t1_re = aIm[0]+aIm[4];
	t2_re = aIm[0]-aIm[4];
	t3_re = aIm[1]-aIm[7];
	t4_re = aIm[1]+aIm[7];
	t5_re = aIm[3]+aIm[5];
	t6_re = aIm[2]-aIm[6];
	t7_re = aIm[2]+aIm[6];
	t8_re = aIm[3]-aIm[5];
	m1_im = t1_re+t7_re;
	t1_re = t1_re-t7_re;
	t7_re = t4_re+t5_re;
	t4_re = (t4_re-t5_re)*tIRT2;

	aIm[0] = m1_im+t7_re;
	aIm[4] = m1_im-t7_re;

	t7_re = t2_re+t4_re;
	t2_re = t2_re-t4_re;
	t4_re = t3_re-t8_re;
	t3_re = (t3_re+t8_re)*tIRT2;
	t5_re = t3_re+t6_re;
	t3_re = t3_re-t6_re;

	aRe[1] = m2_re+t5_re;
	aIm[1] = t7_re-t2_im;
	aRe[2] = m2_im+t4_re;
	aIm[2] = t1_re-t1_im;
	aRe[3] = m1_re+t3_re;
	aIm[3] = t2_re-t4_im;
	aRe[5] = m1_re-t3_re;
	aIm[5] = t2_re+t4_im;
	aRe[6] = m2_im-t4_re;
	aIm[6] = t1_re+t1_im;
	aRe[7] = m2_re-t5_re;
	aIm[7] = t7_re+t2_im;
}


/**
 * length 9 DFT
 */
template<class Type>
inline void FFTPF<Type>::radix9( Type *aRe, Type *aIm )
{
	t1_re = aRe[1]+aRe[8];
	t2_re = aRe[1]-aRe[8];
	t3_re = aRe[2]+aRe[7];
	t4_re = aRe[2]-aRe[7];
	t5_re = aRe[3]+aRe[6];
	ttmp  = aRe[0]+t5_re;
	t7_re = aRe[4]+aRe[5];
	t8_re = aRe[4]-aRe[5];
	t8_im = (aRe[6]-aRe[3])*tIRT3;
	t7_im = aRe[0]+t5_re*c9_5;
	t5_re = t1_re+t3_re+t7_re;

	aRe[0] = ttmp+t5_re;

	t5_im = ttmp+t5_re*c9_5;
	t3_im = (t7_re-t3_re)*c9_2;
	t7_re = (t7_re-t1_re)*c9_3;
	t3_re = (t1_re-t3_re)*c9_4;
	t1_im = t7_im+t3_im+t3_re;
	t3_im = t7_im-t3_im-t7_re;
	t7_im = t7_im+t7_re-t3_re;
	t6_im = (t4_re-t2_re-t8_re)*tIRT3;
	t4_im = (t4_re+t8_re)*c9_6;
	t8_re = (t8_re-t2_re)*c9_7;
	t2_re = (t2_re+t4_re)*c9_8;
	t2_im = t8_im+t4_im+t2_re;
	t4_im = t8_im-t4_im-t8_re;
	t8_im = t8_im+t8_re-t2_re;
	t1_re = aIm[1]+aIm[8];
	t2_re = aIm[1]-aIm[8];
	t3_re = aIm[2]+aIm[7];
	t4_re = aIm[2]-aIm[7];
	t5_re = aIm[3]+aIm[6];
	t6_re = (aIm[6]-aIm[3])*tIRT3;
	t7_re = aIm[4]+aIm[5];
	t8_re = aIm[4]-aIm[5];
	ttmp  = aIm[0]+t5_re;
	t9_im = aIm[0]+t5_re*c9_5;
	t5_re = t1_re+t3_re+t7_re;

	aIm[0] = ttmp+t5_re;

	t5_re = ttmp+t5_re*c9_5;
	ttmp  = (t7_re-t3_re)*c9_2;
	t7_re = (t7_re-t1_re)*c9_3;
	t3_re = (t1_re-t3_re)*c9_4;
	t1_re = t9_im+ttmp+t3_re;
	ttmp  = t9_im-ttmp-t7_re;
	t7_re = t9_im+t7_re-t3_re;
	t9_re = (t4_re-t2_re-t8_re)*tIRT3;
	t3_re = (t4_re+t8_re)*c9_6;
	t8_re = (t8_re-t2_re)*c9_7;
	t4_re = (t2_re+t4_re)*c9_8;
	t2_re = t6_re+t3_re+t4_re;
	t3_re = t6_re-t8_re-t3_re;
	t8_re = t6_re+t8_re-t4_re;

	aRe[1] = t1_im-t2_re;
	aIm[1] = t1_re+t2_im;
	aRe[2] = t3_im+t3_re;
	aIm[2] = ttmp-t4_im;
	aRe[3] = t5_im-t9_re;
	aIm[3] = t5_re+t6_im;
	aRe[4] = t7_im-t8_re;
	aIm[4] = t7_re+t8_im;
	aRe[5] = t7_im+t8_re;
	aIm[5] = t7_re-t8_im;
	aRe[6] = t5_im+t9_re;
	aIm[6] = t5_re-t6_im;
	aRe[7] = t3_im-t3_re;
	aIm[7] = ttmp+t4_im;
	aRe[8] = t1_im+t2_re;
	aIm[8] = t1_re-t2_im;
}


/**
 * length 10 DFT
 */
template<class Type>
inline void FFTPF<Type>::radix10( Type *aRe, Type *aIm )
{
	t1_re = aRe[2]+aRe[8];
	t2_re = aRe[4]-aRe[6];
	t3_re = aRe[2]-aRe[8];
	t4_re = aRe[4]+aRe[6];
	t5_re = (t1_re-t4_re)*c5_1;
	t1_re = t1_re+t4_re;
	m9_re = aRe[0]+t1_re;
	t1_re = m9_re-t1_re*c5_5;
	t4_re = t1_re-t5_re;
	t1_re = t1_re+t5_re;
	t5_re = (t3_re+t2_re)*c5_2;
	t3_re = t5_re-t3_re*c5_4;
	t2_re = t5_re-t2_re*c5_3;
	t1_im = aIm[2]+aIm[8];
	t2_im = aIm[4]-aIm[6];
	t3_im = aIm[2]-aIm[8];
	t4_im = aIm[4]+aIm[6];
	t5_re = (t1_im-t4_im)*c5_1;
	t1_im = t1_im+t4_im;
	m9_im = aIm[0]+t1_im;
	t1_im = m9_im-t1_im*c5_5;
	t4_im = t1_im-t5_re;
	t1_im = t1_im+t5_re;
	t5_re = (t3_im+t2_im)*c5_2;
	t3_im = t5_re-t3_im*c5_4;
	t2_im = t5_re-t2_im*c5_3;
	m1_re = t1_re+t2_im;
	m1_im = t1_im-t2_re;
	m2_re = t4_re-t3_im;
	m2_im = t4_im+t3_re;
	m3_re = t4_re+t3_im;
	m3_im = t4_im-t3_re;
	m4_re = t1_re-t2_im;
	m4_im = t1_im+t2_re;
	t1_re = aRe[7]+aRe[3];
	t2_re = aRe[9]-aRe[1];
	t3_re = aRe[7]-aRe[3];
	t4_re = aRe[9]+aRe[1];
	t5_re = (t1_re-t4_re)*c5_1;
	t1_re = t1_re+t4_re;
	t9_re = aRe[5]+t1_re;
	t1_re = t9_re-t1_re*c5_5;
	t4_re = t1_re-t5_re;
	t1_re = t1_re+t5_re;
	t5_re = (t3_re+t2_re)*c5_2;
	t3_re = t5_re-t3_re*c5_4;
	t2_re = t5_re-t2_re*c5_3;
	t1_im = aIm[7]+aIm[3];
	t2_im = aIm[9]-aIm[1];
	t3_im = aIm[7]-aIm[3];
	t4_im = aIm[9]+aIm[1];
	t5_re = (t1_im-t4_im)*c5_1;
	t1_im = t1_im+t4_im;
	t9_im = aIm[5]+t1_im;
	t1_im = t9_im-t1_im*c5_5;
	t4_im = t1_im-t5_re;
	t1_im = t1_im+t5_re;
	t5_re = (t3_im+t2_im)*c5_2;
	t3_im = t5_re-t3_im*c5_4;
	t2_im = t5_re-t2_im*c5_3;
	m5_re = t1_re+t2_im;
	m5_im = t1_im-t2_re;
	m6_re = t4_re-t3_im;
	m6_im = t4_im+t3_re;
	m7_re = t4_re+t3_im;
	m7_im = t4_im-t3_re;
	m8_re = t1_re-t2_im;
	m8_im = t1_im+t2_re;

	aRe[0] = m9_re+t9_re;
	aIm[0] = m9_im+t9_im;
	aRe[1] = m1_re-m5_re;
	aIm[1] = m1_im-m5_im;
	aRe[2] = m2_re+m6_re;
	aIm[2] = m2_im+m6_im;
	aRe[3] = m3_re-m7_re;
	aIm[3] = m3_im-m7_im;
	aRe[4] = m4_re+m8_re;
	aIm[4] = m4_im+m8_im;
	aRe[5] = m9_re-t9_re;
	aIm[5] = m9_im-t9_im;
	aRe[6] = m1_re+m5_re;
	aIm[6] = m1_im+m5_im;
	aRe[7] = m2_re-m6_re;
	aIm[7] = m2_im-m6_im;
	aRe[8] = m3_re+m7_re;
	aIm[8] = m3_im+m7_im;
	aRe[9] = m4_re-m8_re;
	aIm[9] = m4_im-m8_im;
}


/**
 * length 11 DFT
 */
template<class Type>
inline void FFTPF<Type>::radix11( Type *aRe, Type *aIm )
{
	t1_re = aRe[1]+aRe[10];
	t1_im = aIm[1]+aIm[10];
	t2_re = aRe[2]+aRe[9];
	t2_im = aIm[2]+aIm[9];
	t3_re = aRe[3]+aRe[8];
	t3_im = aIm[3]+aIm[8];
	t4_re = aRe[4]+aRe[7];
	t4_im = aIm[4]+aIm[7];
	t5_re = aRe[5]+aRe[6];
	t5_im = aIm[5]+aIm[6];
	t6_re = aRe[10]-aRe[1];
	t6_im = aIm[10]-aIm[1];
	t7_re = aRe[9]-aRe[2];
	t7_im = aIm[9]-aIm[2];
	t8_re = aRe[8]-aRe[3];
	t8_im = aIm[8]-aIm[3];
	t9_re = aRe[7]-aRe[4];
	t9_im = aIm[7]-aIm[4];
	t10_re = aRe[6]-aRe[5];
	t10_im = aIm[6]-aIm[5];
	t11_re = aRe[0]-Type(0.5*t5_re);
	t11_im = aIm[0]-Type(0.5*t5_im);
	t12_re = t1_re-t5_re;
	t12_im = t1_im-t5_im;
	t13_re = t2_re-t5_re;
	t13_im = t2_im-t5_im;
	t14_re = t3_re-t5_re;
	t14_im = t3_im-t5_im;
	t15_re = t4_re-t5_re;
	t15_im =  t4_im-t5_im;

	m1_re = t11_re+c11_1*t12_re+c11_2*t13_re+c11_3*t14_re+c11_4*t15_re;
	m1_im = t11_im+c11_1*t12_im+c11_2*t13_im+c11_3*t14_im+c11_4*t15_im;
	m2_re = t11_re+c11_2*t12_re+c11_4*t13_re+c11_5*t14_re+c11_3*t15_re;
	m2_im = t11_im+c11_2*t12_im+c11_4*t13_im+c11_5*t14_im+c11_3*t15_im;
	m3_re = t11_re+c11_3*t12_re+c11_5*t13_re+c11_2*t14_re+c11_1*t15_re;
	m3_im = t11_im+c11_3*t12_im+c11_5*t13_im+c11_2*t14_im+c11_1*t15_im;
	m4_re = t11_re+c11_4*t12_re+c11_3*t13_re+c11_1*t14_re+c11_5*t15_re;
	m4_im = t11_im+c11_4*t12_im+c11_3*t13_im+c11_1*t14_im+c11_5*t15_im;
	m5_re = t11_re+c11_5*t12_re+c11_1*t13_re+c11_4*t14_re+c11_2*t15_re;
	m5_im = t11_im+c11_5*t12_im+c11_1*t13_im+c11_4*t14_im+c11_2*t15_im;
	m6_re = c11_10*t6_re-c11_6*t7_re+c11_9*t8_re-c11_7*t9_re+c11_8*t10_re;
	m6_im = c11_10*t6_im-c11_6*t7_im+c11_9*t8_im-c11_7*t9_im+c11_8*t10_im;
	m7_re = c11_9*t6_re-c11_8*t7_re+c11_6*t8_re+c11_10*t9_re-c11_7*t10_re;
	m7_im = c11_9*t6_im-c11_8*t7_im+c11_6*t8_im+c11_10*t9_im-c11_7*t10_im;
	m8_re = c11_8*t6_re-c11_10*t7_re-c11_7*t8_re+c11_6*t9_re+c11_9*t10_re;
	m8_im = c11_8*t6_im-c11_10*t7_im-c11_7*t8_im+c11_6*t9_im+c11_9*t10_im;
	m9_re = c11_7*t6_re+c11_9*t7_re-c11_10*t8_re-c11_8*t9_re-c11_6*t10_re;
	m9_im = c11_7*t6_im+c11_9*t7_im-c11_10*t8_im-c11_8*t9_im-c11_6*t10_im;
	m10_re = c11_6*t6_re+c11_7*t7_re+c11_8*t8_re+c11_9*t9_re+c11_10*t10_re;
	m10_im = c11_6*t6_im+c11_7*t7_im+c11_8*t8_im+c11_9*t9_im+c11_10*t10_im;

	aRe[0] = aRe[0]+t1_re+t2_re+t3_re+t4_re+t5_re;
	aIm[0] = aIm[0]+t1_im+t2_im+t3_im+t4_im+t5_im;
	aRe[1] = m1_re-m10_im;
	aIm[1] = m1_im+m10_re;
	aRe[2] = m2_re-m9_im;
	aIm[2] = m2_im+m9_re;
	aRe[3] = m3_re-m8_im;
	aIm[3] = m3_im+m8_re;
	aRe[4] = m4_re-m7_im;
	aIm[4] = m4_im+m7_re;
	aRe[5] = m5_re-m6_im;
	aIm[5] = m5_im+m6_re;
	aRe[6] = m5_re+m6_im;
	aIm[6] = m5_im-m6_re;
	aRe[7] = m4_re+m7_im;
	aIm[7] = m4_im-m7_re;
	aRe[8] = m3_re+m8_im;
	aIm[8] = m3_im-m8_re;
	aRe[9] = m2_re+m9_im;
	aIm[9] = m2_im-m9_re;
	aRe[10] = m1_re+m10_im;
	aIm[10] = m1_im-m10_re;
}


/**
 * length 13 DFT
 */
template<class Type>
inline void FFTPF<Type>::radix13( Type *aRe, Type *aIm )
{
	t1_re = aRe[1]+aRe[12];
	t1_im = aIm[1]+aIm[12];
	t2_re = aRe[2]+aRe[11];
	t2_im = aIm[2]+aIm[11];
	t3_re = aRe[3]+aRe[10];
	t3_im = aIm[3]+aIm[10];
	t4_re = aRe[4]+aRe[9];
	t4_im = aIm[4]+aIm[9];
	t5_re = aRe[5]+aRe[8];
	t5_im = aIm[5]+aIm[8];
	t6_re = aRe[6]+aRe[7];
	t6_im = aIm[6]+aIm[7];
	t7_re = aRe[12]-aRe[1];
	t7_im = aIm[12]-aIm[1];
	t8_re = aRe[11]-aRe[2];
	t8_im = aIm[11]-aIm[2];
	t9_re = aRe[10]-aRe[3];
	t9_im = aIm[10]-aIm[3];
	t10_re = aRe[9]-aRe[4];
	t10_im = aIm[9]-aIm[4];
	t11_re = aRe[8]-aRe[5];
	t11_im = aIm[8]-aIm[5];
	t12_re = aRe[7]-aRe[6];
	t12_im = aIm[7]-aIm[6];
	t13_re = aRe[0]-Type(0.5*t6_re);
	t13_im = aIm[0]-Type(0.5*t6_im);
	t14_re = t1_re-t6_re;
	t14_im = t1_im-t6_im;
	t15_re = t2_re-t6_re;
	t15_im = t2_im-t6_im;
	t16_re = t3_re-t6_re;
	t16_im = t3_im-t6_im;
	t17_re = t4_re-t6_re;
	t17_im = t4_im-t6_im;
	t18_re = t5_re-t6_re;
	t18_im = t5_im-t6_im;

	m1_re = t13_re + c13_1*t14_re + c13_2*t15_re + c13_3*t16_re +
            c13_4*t17_re + c13_5*t18_re;
	m1_im = t13_im + c13_1*t14_im + c13_2*t15_im + c13_3*t16_im +
            c13_4*t17_im + c13_5*t18_im;
	m2_re = t13_re + c13_2*t14_re + c13_4*t15_re + c13_6*t16_re +
            c13_5*t17_re + c13_3*t18_re;
	m2_im = t13_im + c13_2*t14_im + c13_4*t15_im + c13_6*t16_im +
            c13_5*t17_im + c13_3*t18_im;
	m3_re = t13_re + c13_3*t14_re + c13_6*t15_re + c13_4*t16_re +
            c13_1*t17_re + c13_2*t18_re;
	m3_im = t13_im + c13_3*t14_im + c13_6*t15_im + c13_4*t16_im +
            c13_1*t17_im + c13_2*t18_im;
	m4_re = t13_re + c13_4*t14_re + c13_5*t15_re + c13_1*t16_re +
            c13_3*t17_re + c13_6*t18_re;
	m4_im = t13_im + c13_4*t14_im + c13_5*t15_im + c13_1*t16_im +
            c13_3*t17_im + c13_6*t18_im;
	m5_re = t13_re + c13_5*t14_re + c13_3*t15_re + c13_2*t16_re +
            c13_6*t17_re + c13_1*t18_re;
	m5_im = t13_im + c13_5*t14_im + c13_3*t15_im + c13_2*t16_im +
            c13_6*t17_im + c13_1*t18_im;
	m6_re = t13_re + c13_6*t14_re + c13_1*t15_re + c13_5*t16_re +
            c13_2*t17_re + c13_4*t18_re;
	m6_im = t13_im + c13_6*t14_im + c13_1*t15_im + c13_5*t16_im +
            c13_2*t17_im + c13_4*t18_im;
	m7_re = c13_12*t7_re - c13_7*t8_re + c13_11*t9_re - c13_8*t10_re +
            c13_10*t11_re - c13_9*t12_re;
	m7_im = c13_12*t7_im - c13_7*t8_im + c13_11*t9_im - c13_8*t10_im +
            c13_10*t11_im - c13_9*t12_im;
	m8_re = c13_11*t7_re - c13_9*t8_re + c13_8*t9_re - c13_12*t10_re -
            c13_7*t11_re + c13_10*t12_re;
	m8_im = c13_11*t7_im - c13_9*t8_im + c13_8*t9_im - c13_12*t10_im -
            c13_7*t11_im + c13_10*t12_im;
	m9_re = c13_10*t7_re - c13_11*t8_re - c13_7*t9_re + c13_9*t10_re -
            c13_12*t11_re - c13_8*t12_re;
	m9_im = c13_10*t7_im - c13_11*t8_im - c13_7*t9_im + c13_9*t10_im -
            c13_12*t11_im - c13_8*t12_im;
	m10_re = c13_9*t7_re + c13_12*t8_re - c13_10*t9_re - c13_7*t10_re +
	         c13_8*t11_re + c13_11*t12_re;
	m10_im = c13_9*t7_im + c13_12*t8_im - c13_10*t9_im - c13_7*t10_im +
	         c13_8*t11_im + c13_11*t12_im;
	m11_re = c13_8*t7_re + c13_10*t8_re + c13_12*t9_re - c13_11*t10_re -
	         c13_9*t11_re - c13_7*t12_re;
	m11_im = c13_8*t7_im + c13_10*t8_im + c13_12*t9_im - c13_11*t10_im -
             c13_9*t11_im - c13_7*t12_im;
	m12_re = c13_7*t7_re + c13_8*t8_re + c13_9*t9_re + c13_10*t10_re +
             c13_11*t11_re + c13_12*t12_re;
	m12_im = c13_7*t7_im + c13_8*t8_im + c13_9*t9_im + c13_10*t10_im +
             c13_11*t11_im + c13_12*t12_im;

	aRe[0] = aRe[0]+t1_re+t2_re+t3_re+t4_re+t5_re+t6_re;
	aIm[0] = aIm[0]+t1_im+t2_im+t3_im+t4_im+t5_im+t6_im;
	aRe[1] = m1_re-m12_im;
	aIm[1] = m1_im+m12_re;
	aRe[2] = m2_re-m11_im;
	aIm[2] = m2_im+m11_re;
	aRe[3] = m3_re-m10_im;
	aIm[3] = m3_im+m10_re;
	aRe[4] = m4_re-m9_im;
	aIm[4] = m4_im+m9_re;
	aRe[5] = m5_re-m8_im;
	aIm[5] = m5_im+m8_re;
	aRe[6] = m6_re-m7_im;
	aIm[6] = m6_im+m7_re;
	aRe[7] = m6_re+m7_im;
	aIm[7] = m6_im-m7_re;
	aRe[8] = m5_re+m8_im;
	aIm[8] = m5_im-m8_re;
	aRe[9] = m4_re+m9_im;
	aIm[9] = m4_im-m9_re;
	aRe[10] = m3_re+m10_im;
	aIm[10] = m3_im-m10_re;
	aRe[11] = m2_re+m11_im;
	aIm[11] = m2_im-m11_re;
	aRe[12] = m1_re+m12_im;
	aIm[12] = m1_im-m12_re;
}


/**
 * length 16 DFT
 */
template<class Type>
inline void FFTPF<Type>::radix16( Type *aRe, Type *aIm )
{
	t1_re = aRe[0]+aRe[8];
	t2_re = aRe[0]-aRe[8];
	t3_re = aRe[1]+aRe[9];
	t4_re = aRe[1]-aRe[9];
	t5_re = aRe[2]+aRe[10];
	t6_re = aRe[2]-aRe[10];
	t7_re = aRe[3]+aRe[11];
	t8_re = aRe[3]-aRe[11];
	t9_re = aRe[4]+aRe[12];
	t10_re = aRe[4]-aRe[12];
	t11_re = aRe[5]+aRe[13];
	t12_re = aRe[5]-aRe[13];
	t13_re = aRe[6]+aRe[14];
	t14_re = aRe[6]-aRe[14];
	t15_re = aRe[7]+aRe[15];
	t16_re = aRe[7]-aRe[15];
	t1_im = t1_re+t9_re;
	t2_im = t1_re-t9_re;
	t3_im = t3_re+t11_re;
	t4_im = t3_re-t11_re;
	t5_im = t5_re+t13_re;
	t6_im = t5_re-t13_re;
	t7_im = t7_re+t15_re;
	t8_im = t7_re-t15_re;
	t1_re = t1_im+t5_im;
	t3_re = t1_im-t5_im;
	t5_re = t3_im+t7_im;
	t7_re = t3_im-t7_im;

	aRe[0] = t1_re+t5_re;
	aRe[8] = t1_re-t5_re;

	t1_im = tIRT2*(t4_im+t8_im);
	t5_im = tIRT2*(t4_im-t8_im);
	t9_re = t2_im+t5_im;
	t11_re = t2_im-t5_im;
	t13_re = t6_im+t1_im;
	t15_re = t6_im-t1_im;
	t1_im = t4_re+t16_re;
	t2_im = t4_re-t16_re;
	t3_im = tIRT2*(t6_re+t14_re);
	t4_im = tIRT2*(t6_re-t14_re);
	t5_im = t8_re+t12_re;
	t6_im = t8_re-t12_re;
	t7_im = c16_2*(t2_im-t6_im);
	t2_im = c16_3*t2_im-t7_im;
	t6_im = c16_4*t6_im-t7_im;
	t7_im = t2_re+t4_im;
	t8_im = t2_re-t4_im;
	t2_re = t7_im+t2_im;
	t4_re = t7_im-t2_im;
	t6_re = t8_im+t6_im;
	t8_re = t8_im-t6_im;
	t7_im = c16_5*(t1_im+t5_im);
	t2_im = t7_im-c16_4*t1_im;
	t4_im = t7_im-c16_3*t5_im;
	t6_im = t10_re+t3_im;
	t8_im = t10_re-t3_im;
	t10_re = t6_im+t2_im;
	t12_re = t6_im-t2_im;
	t14_re = t8_im+t4_im;
	t16_re = t8_im-t4_im;
	t1_re = aIm[0]+aIm[8];
	t9_im = aIm[0]-aIm[8];
	t10_im = aIm[1]+aIm[9];
	t11_im = aIm[1]-aIm[9];
	t5_re = aIm[2]+aIm[10];
	t12_im = aIm[2]-aIm[10];
	t13_im = aIm[3]+aIm[11];
	t14_im = aIm[3]-aIm[11];
	t15_im = aIm[4]+aIm[12];
	t16_im = aIm[4]-aIm[12];
	t17_im = aIm[5]+aIm[13];
	t18_im = aIm[5]-aIm[13];
	t19_im = aIm[6]+aIm[14];
	t20_im = aIm[6]-aIm[14];
	t21_im = aIm[7]+aIm[15];
	t22_im = aIm[7]-aIm[15];
	t1_im = t1_re+t15_im;
	t2_im = t1_re-t15_im;
	t3_im = t10_im+t17_im;
	t4_im = t10_im-t17_im;
	t5_im = t5_re+t19_im;
	t6_im = t5_re-t19_im;
	t7_im = t13_im+t21_im;
	t8_im = t13_im-t21_im;
	t1_re = t1_im+t5_im;
	t10_im = t1_im-t5_im;
	t5_re = t3_im+t7_im;
	t13_im = t3_im-t7_im;

	aIm[0] = t1_re+t5_re;
	aIm[8] = t1_re-t5_re;
	aRe[4] = t3_re+t13_im;
	aIm[4] = t10_im-t7_re;
	aRe[12] = t3_re-t13_im;
	aIm[12] = t10_im+t7_re;

	t1_im = tIRT2*(t4_im+t8_im);
	t5_im = tIRT2*(t4_im-t8_im);
	t15_im = t2_im+t5_im;
	t17_im = t2_im-t5_im;
	t19_im = t6_im+t1_im;
	t21_im = t6_im-t1_im;
	t1_im = t11_im+t22_im;
	t2_im = t11_im-t22_im;
	t3_im = tIRT2*(t12_im+t20_im);
	t4_im = tIRT2*(t12_im-t20_im);
	t5_im = t14_im+t18_im;
	t6_im = t14_im-t18_im;
	t7_im = c16_2*(t2_im-t6_im);
	t2_im = c16_3*t2_im-t7_im;
	t6_im = c16_4*t6_im-t7_im;
	t7_im = t9_im+t4_im;
	t8_im = t9_im-t4_im;
	t9_im = t7_im+t2_im;
	t11_im = t7_im-t2_im;
	t12_im = t8_im+t6_im;
	t14_im = t8_im-t6_im;
	t7_im = c16_5*(t1_im+t5_im);
	t2_im = t7_im-c16_4*t1_im;
	t4_im = t7_im-c16_3*t5_im;
	t6_im = t16_im+t3_im;
	t8_im = t16_im-t3_im;
	t16_im = t6_im+t2_im;
	t18_im = t6_im-t2_im;
	t20_im = t8_im+t4_im;
	t22_im = t8_im-t4_im;

	aRe[1] = t2_re+t16_im;
	aIm[1] = t9_im-t10_re;
	aRe[2] = t9_re+t19_im;
	aIm[2] = t15_im-t13_re;
	aRe[3] = t8_re-t22_im;
	aIm[3] = t14_im+t16_re;
	aRe[5] = t6_re+t20_im;
	aIm[5] = t12_im-t14_re;
	aRe[6] = t11_re-t21_im;
	aIm[6] = t17_im+t15_re;
	aRe[7] = t4_re-t18_im;
	aIm[7] = t11_im+t12_re;
	aRe[9] = t4_re+t18_im;
	aIm[9] = t11_im-t12_re;
	aRe[10] = t11_re+t21_im;
	aIm[10] = t17_im-t15_re;
	aRe[11] = t6_re-t20_im;
	aIm[11] = t12_im+t14_re;
	aRe[13] = t8_re+t22_im;
	aIm[13] = t14_im-t16_re;
	aRe[14] = t9_re-t19_im;
	aIm[14] = t15_im+t13_re;
	aRe[15] = t2_re-t16_im;
	aIm[15] = t9_im+t10_re;
}


/**
 * other length DFT
 */
template<class Type>
inline void FFTPF<Type>::radixOther( int radix )
{
	Type    rere, reim, imre, imim;
	int     i, j, k, n, max;

	n = radix;
	max = (n+1)/2;

	for( j=1; j<max; ++j )
	{
		pfvRe[j] = pfzRe[j]+pfzRe[n-j];
		pfvIm[j] = pfzIm[j]-pfzIm[n-j];
		pfwRe[j] = pfzRe[j]-pfzRe[n-j];
		pfwIm[j] = pfzIm[j]+pfzIm[n-j];
	}

	for( j=1; j<max; ++j )
	{
		pfzRe[j] = pfzRe[0];
		pfzIm[j] = pfzIm[0];
		pfzRe[n-j] = pfzRe[0];
		pfzIm[n-j] = pfzIm[0];
		k = j;
		for( i=1; i<max; ++i )
		{
			rere = pftgRe[k]*pfvRe[i];
			imim = pftgIm[k]*pfvIm[i];
			reim = pftgRe[k]*pfwIm[i];
			imre = pftgIm[k]*pfwRe[i];

			pfzRe[n-j] += rere+imim;
			pfzIm[n-j] += reim-imre;
			pfzRe[j] += rere-imim;
			pfzIm[j] += reim+imre;

			k = k+j;
			if( k >= n )
                k = k-n;
		}
	}

	for( j=1; j<max; ++j )
	{
		pfzRe[0] = pfzRe[0]+pfvRe[j];
		pfzIm[0] = pfzIm[0]+pfwIm[j];
	}
}

/**
 * twiddle multiplications and DFT's for one stage.
 */
template<class Type>
void FFTPF<Type>::twiddleFFT( int sofarRadix, int radix, int remainRadix,
                              Vector< complex<Type> > &yn )
{
	Type   cosw, sinw;
	initTrig( radix );

	omega = 2*tPI/(Type)(sofarRadix*radix);
	cosw  = Type(cos(omega));
	sinw  = -Type(sin(omega));
	twRe  = 1;
	twIim = 0;
	dataOffset = 0;
    groupOffset = dataOffset;
    adr = groupOffset;

	for( dataNo=0; dataNo<sofarRadix; ++dataNo )
	{
		if( sofarRadix > 1 )
		{
			pftwRe[0] = 1;
			pftwIm[0] = 0;
			pftwRe[1] = twRe;
			pftwIm[1] = twIim;

			for( twNo=2; twNo<radix; ++twNo )
			{
				pftwRe[twNo] = twRe*pftwRe[twNo-1]-twIim*pftwIm[twNo-1];
				pftwIm[twNo] = twIim*pftwRe[twNo-1]+twRe*pftwIm[twNo-1];
			}
			ttmp = cosw*twRe-sinw*twIim;
			twIim = sinw*twRe+cosw*twIim;
			twRe = ttmp;
		}

		for( groupNo=0; groupNo<remainRadix; ++groupNo )
		{
			if( (sofarRadix>1) && (dataNo>0) )
			{
				pfzRe[0] = yn[adr].real();
				pfzIm[0] = yn[adr].imag();
				blockNo = 1;
				do
				{
					adr += sofarRadix;
					pfzRe[blockNo] = pftwRe[blockNo]*yn[adr].real() -
                                     pftwIm[blockNo]*yn[adr].imag();
					pfzIm[blockNo] = pftwRe[blockNo]*yn[adr].imag() +
                                     pftwIm[blockNo]*yn[adr].real();
					blockNo++;
				}
				while( blockNo < radix );
			}
			else
                for( blockNo=0; blockNo<radix; ++blockNo )
                {
                    pfzRe[blockNo] = yn[adr].real();
                    pfzIm[blockNo] = yn[adr].imag();
                    adr = adr+sofarRadix;
                }

			switch( radix )
			{
                case 2 :
                    radix2( pfzRe, pfzIm );
                    break;
                case 3 :
                    radix3( pfzRe, pfzIm );
                    break;
                case 4 :
                    radix4( pfzRe, pfzIm );
                    break;
                case 5 :
                    radix5( pfzRe, pfzIm );
                    break;
                case 7 :
                    radix7( pfzRe, pfzIm );
                    break;
                case 8 :
                    radix8( pfzRe, pfzIm );
                    break;
                case 9 :
                    radix9( pfzRe, pfzIm );
                    break;
                case 10 :
                    radix10( pfzRe, pfzIm );
                    break;
                case 11 :
                    radix11( pfzRe, pfzIm );
                    break;
                case 13 :
                    radix13( pfzRe, pfzIm );
                    break;
                case 16 :
                    radix16( pfzRe, pfzIm );
                    break;
                default :
                    radixOther( radix );
                    break;
			}

			adr = groupOffset;
			for( blockNo=0; blockNo<radix; ++blockNo )
			{
                yn[adr] = complex<Type>( pfzRe[blockNo], pfzIm[blockNo] );
				adr += sofarRadix;
			}
			groupOffset += sofarRadix*radix;
			adr = groupOffset;
		}

		dataOffset = dataOffset+1;
		groupOffset = dataOffset;
		adr = groupOffset;
	}
}


/**
 * forward transform
 */
template<class Type>
void FFTPF<Type>::fft( const Vector<Type> &xn, Vector< complex<Type> > &Xk )
{
    int n = xn.size();
	if( n != mNOldSize )
        primeSetup( n );

	permute( xn, Xk );

	for( int i=1; i<=mNFactor; ++i )
		twiddleFFT( mSofarRadix[i], mActualRadix[i], mRemainRadix[i], Xk );
}

template<class Type>
void FFTPF<Type>::fft( const Vector< complex<Type> > &xn,
                       Vector< complex<Type> > &Xk )
{
    int n = xn.size();
	if( n != mNOldSize )
        primeSetup( n );

	permute( xn, Xk, true );

	for( int i=1; i<=mNFactor; ++i )
		twiddleFFT( mSofarRadix[i], mActualRadix[i], mRemainRadix[i], Xk );
}


/**
 * inverse transform
 */
template<class Type>
void FFTPF<Type>::ifft( const Vector< complex<Type> > &Xk, Vector<Type> &xn )
{
    int n = xn.size();
	if( n != mNOldSize )
        primeSetup( n );

    Vector< complex<Type> > Yk(n);
	permute( Xk, Yk, false );

	for( int i=1; i<=mNFactor; ++i )
		twiddleFFT( mSofarRadix[i], mActualRadix[i], mRemainRadix[i], Yk );

    for( int i=0; i<n; ++i )
        xn[i] = Yk[i].real() / Type(n);
}

template<class Type>
void FFTPF<Type>::ifft( const Vector< complex<Type> > &Xk,
                        Vector< complex<Type> > &xn )
{
    int n = xn.size();
	if( n != mNOldSize )
        primeSetup( n );

	permute( Xk, xn, false );

	for( int i=1; i<=mNFactor; ++i )
		twiddleFFT( mSofarRadix[i], mActualRadix[i], mRemainRadix[i], xn );

    for( int i=0; i<n; ++i )
        xn[i] = conj(xn[i]) / Type(n);
}

测试代码:

/*****************************************************************************
 *                               fftpf_test.cpp
 *
 * Prime factor FFT test.
 *
 * Zhang Ming, 2010-09, Xi'an Jiaotong University.
 *****************************************************************************/


#include <iostream>
#include <cstdlib>
#include <vectormath.h>
#include <fftpf.h>


using namespace std;
using namespace splab;


typedef double  Type;
const   int     MINLEN = 101;
const   int     MAXLEN = 1000;
const   int     STEP   = 10;


int main()
{
	Vector< complex<Type> >  sn, Rk, Sk, xn;
	Vector<Type> rn, tn;
    FFTPF<Type> Fourier;

    cout << "forward transform: Sk = fft(sn)  ( complex to complex )." << endl;
	cout << "inverse transform: xn = ifft(Sk) ( complex to complex )." << endl << endl;
	for( int len=MINLEN; len<MAXLEN; len+=STEP )
	{
	    sn.resize(len);
	    Sk.resize(len);
	    xn.resize(len);
	    for( int i=0; i<len; ++i )
            sn[i] = complex<Type>( rand()%10, rand()%10 );

        Fourier.fft( sn, Sk );
        Fourier.ifft( Sk, xn );
        cout << "N = " << len << "\t\t" << "mean(abs((sn-xn)) = "
             << sum(abs(sn-xn))/len << endl;
	}
    cout << endl << endl;

    cout << "forward transform: Rk = fft(rn)  ( real to complex )." << endl;
	cout << "inverse transform: tn = ifft(Rk) ( complex to real )." << endl << endl;;
    for( int len=MINLEN; len<MAXLEN; len+=STEP )
	{
	    rn.resize(len);
	    Rk.resize(len);
	    tn.resize(len);
	    for( int i=0; i<len; ++i )
            rn[i] = rand()%10;

        Fourier.fft( rn, Rk );
        Fourier.ifft( Rk, tn );
        cout << "N = " << len << "\t\t" << "mean(abs((rn-tn)) = "
             << sum(abs(sn-xn))/len << endl;
	}
	cout << endl;

	return 0;
}

运行结果:

forward transform: Sk = fft(sn)  ( complex to complex ).
inverse transform: xn = ifft(Sk) ( complex to complex ).

N = 101         mean(abs((sn-xn)) = 9.56796e-015
N = 111         mean(abs((sn-xn)) = 6.02908e-015
N = 121         mean(abs((sn-xn)) = 3.68512e-015
N = 131         mean(abs((sn-xn)) = 2.0032e-014
N = 141         mean(abs((sn-xn)) = 8.53139e-015
N = 151         mean(abs((sn-xn)) = 1.32487e-014
N = 161         mean(abs((sn-xn)) = 6.01949e-015
N = 171         mean(abs((sn-xn)) = 9.78613e-015
N = 181         mean(abs((sn-xn)) = 4.90428e-015
N = 191         mean(abs((sn-xn)) = 1.28095e-014
N = 201         mean(abs((sn-xn)) = 7.66037e-015
N = 211         mean(abs((sn-xn)) = 2.64879e-014
N = 221         mean(abs((sn-xn)) = 1.23744e-014
N = 231         mean(abs((sn-xn)) = 1.52028e-014
N = 241         mean(abs((sn-xn)) = 1.48443e-014
N = 251         mean(abs((sn-xn)) = 2.23183e-014
N = 261         mean(abs((sn-xn)) = 1.19937e-014
N = 271         mean(abs((sn-xn)) = 1.54789e-014
N = 281         mean(abs((sn-xn)) = 6.37825e-014
N = 291         mean(abs((sn-xn)) = 6.81017e-015
N = 301         mean(abs((sn-xn)) = 3.67519e-014
N = 311         mean(abs((sn-xn)) = 7.74232e-014
N = 321         mean(abs((sn-xn)) = 2.06363e-014
N = 331         mean(abs((sn-xn)) = 2.6944e-014
N = 341         mean(abs((sn-xn)) = 2.32377e-014
N = 351         mean(abs((sn-xn)) = 1.81853e-014
N = 361         mean(abs((sn-xn)) = 2.70795e-014
N = 371         mean(abs((sn-xn)) = 8.89281e-015
N = 381         mean(abs((sn-xn)) = 1.1903e-014
N = 391         mean(abs((sn-xn)) = 9.39787e-015
N = 401         mean(abs((sn-xn)) = 6.26719e-014
N = 411         mean(abs((sn-xn)) = 1.56459e-014
N = 421         mean(abs((sn-xn)) = 5.49224e-014
N = 431         mean(abs((sn-xn)) = 7.13155e-014
N = 441         mean(abs((sn-xn)) = 7.9457e-015
N = 451         mean(abs((sn-xn)) = 2.90133e-014
N = 461         mean(abs((sn-xn)) = 5.84939e-014
N = 471         mean(abs((sn-xn)) = 4.29465e-014
N = 481         mean(abs((sn-xn)) = 4.52387e-014
N = 491         mean(abs((sn-xn)) = 1.10306e-013
N = 501         mean(abs((sn-xn)) = 3.37587e-014
N = 511         mean(abs((sn-xn)) = 4.57228e-014
N = 521         mean(abs((sn-xn)) = 1.11653e-013
N = 531         mean(abs((sn-xn)) = 5.84668e-014
N = 541         mean(abs((sn-xn)) = 1.27624e-013
N = 551         mean(abs((sn-xn)) = 3.54317e-014
N = 561         mean(abs((sn-xn)) = 5.29495e-014
N = 571         mean(abs((sn-xn)) = 3.74233e-014
N = 581         mean(abs((sn-xn)) = 3.8153e-014
N = 591         mean(abs((sn-xn)) = 3.24913e-014
N = 601         mean(abs((sn-xn)) = 1.32896e-013
N = 611         mean(abs((sn-xn)) = 2.92566e-014
N = 621         mean(abs((sn-xn)) = 4.35837e-014
N = 631         mean(abs((sn-xn)) = 1.35408e-013
N = 641         mean(abs((sn-xn)) = 1.35158e-013
N = 651         mean(abs((sn-xn)) = 1.38349e-014
N = 661         mean(abs((sn-xn)) = 1.30397e-013
N = 671         mean(abs((sn-xn)) = 2.18791e-014
N = 681         mean(abs((sn-xn)) = 7.84698e-014
N = 691         mean(abs((sn-xn)) = 1.38373e-013
N = 701         mean(abs((sn-xn)) = 1.66637e-013
N = 711         mean(abs((sn-xn)) = 2.22414e-014
N = 721         mean(abs((sn-xn)) = 3.17155e-014
N = 731         mean(abs((sn-xn)) = 4.88291e-014
N = 741         mean(abs((sn-xn)) = 6.79333e-014
N = 751         mean(abs((sn-xn)) = 6.76077e-014
N = 761         mean(abs((sn-xn)) = 1.4751e-013
N = 771         mean(abs((sn-xn)) = 3.765e-014
N = 781         mean(abs((sn-xn)) = 4.03454e-014
N = 791         mean(abs((sn-xn)) = 3.66948e-014
N = 801         mean(abs((sn-xn)) = 8.22744e-014
N = 811         mean(abs((sn-xn)) = 1.90965e-014
N = 821         mean(abs((sn-xn)) = 1.775e-013
N = 831         mean(abs((sn-xn)) = 1.52596e-014
N = 841         mean(abs((sn-xn)) = 9.06967e-014
N = 851         mean(abs((sn-xn)) = 8.87579e-014
N = 861         mean(abs((sn-xn)) = 6.5877e-015
N = 871         mean(abs((sn-xn)) = 2.90611e-014
N = 881         mean(abs((sn-xn)) = 1.11084e-013
N = 891         mean(abs((sn-xn)) = 2.36818e-014
N = 901         mean(abs((sn-xn)) = 8.32884e-014
N = 911         mean(abs((sn-xn)) = 1.32497e-013
N = 921         mean(abs((sn-xn)) = 5.2289e-014
N = 931         mean(abs((sn-xn)) = 6.6602e-014
N = 941         mean(abs((sn-xn)) = 4.79529e-014
N = 951         mean(abs((sn-xn)) = 5.12486e-014
N = 961         mean(abs((sn-xn)) = 1.3465e-013
N = 971         mean(abs((sn-xn)) = 1.80164e-013
N = 981         mean(abs((sn-xn)) = 8.43108e-014
N = 991         mean(abs((sn-xn)) = 4.85968e-014


forward transform: Rk = fft(rn)  ( real to complex ).
inverse transform: tn = ifft(Rk) ( complex to real ).

N = 101         mean(abs((rn-tn)) = 4.76826e-013
N = 111         mean(abs((rn-tn)) = 4.33869e-013
N = 121         mean(abs((rn-tn)) = 3.98012e-013
N = 131         mean(abs((rn-tn)) = 3.67629e-013
N = 141         mean(abs((rn-tn)) = 3.41556e-013
N = 151         mean(abs((rn-tn)) = 3.18937e-013
N = 161         mean(abs((rn-tn)) = 2.99127e-013
N = 171         mean(abs((rn-tn)) = 2.81634e-013
N = 181         mean(abs((rn-tn)) = 2.66074e-013
N = 191         mean(abs((rn-tn)) = 2.52144e-013
N = 201         mean(abs((rn-tn)) = 2.39599e-013
N = 211         mean(abs((rn-tn)) = 2.28244e-013
N = 221         mean(abs((rn-tn)) = 2.17916e-013
N = 231         mean(abs((rn-tn)) = 2.08482e-013
N = 241         mean(abs((rn-tn)) = 1.99832e-013
N = 251         mean(abs((rn-tn)) = 1.9187e-013
N = 261         mean(abs((rn-tn)) = 1.84519e-013
N = 271         mean(abs((rn-tn)) = 1.7771e-013
N = 281         mean(abs((rn-tn)) = 1.71386e-013
N = 291         mean(abs((rn-tn)) = 1.65496e-013
N = 301         mean(abs((rn-tn)) = 1.59998e-013
N = 311         mean(abs((rn-tn)) = 1.54853e-013
N = 321         mean(abs((rn-tn)) = 1.50029e-013
N = 331         mean(abs((rn-tn)) = 1.45497e-013
N = 341         mean(abs((rn-tn)) = 1.4123e-013
N = 351         mean(abs((rn-tn)) = 1.37206e-013
N = 361         mean(abs((rn-tn)) = 1.33406e-013
N = 371         mean(abs((rn-tn)) = 1.2981e-013
N = 381         mean(abs((rn-tn)) = 1.26403e-013
N = 391         mean(abs((rn-tn)) = 1.2317e-013
N = 401         mean(abs((rn-tn)) = 1.20098e-013
N = 411         mean(abs((rn-tn)) = 1.17176e-013
N = 421         mean(abs((rn-tn)) = 1.14393e-013
N = 431         mean(abs((rn-tn)) = 1.11739e-013
N = 441         mean(abs((rn-tn)) = 1.09205e-013
N = 451         mean(abs((rn-tn)) = 1.06784e-013
N = 461         mean(abs((rn-tn)) = 1.04467e-013
N = 471         mean(abs((rn-tn)) = 1.02249e-013
N = 481         mean(abs((rn-tn)) = 1.00124e-013
N = 491         mean(abs((rn-tn)) = 9.80844e-014
N = 501         mean(abs((rn-tn)) = 9.61266e-014
N = 511         mean(abs((rn-tn)) = 9.42455e-014
N = 521         mean(abs((rn-tn)) = 9.24365e-014
N = 531         mean(abs((rn-tn)) = 9.06957e-014
N = 541         mean(abs((rn-tn)) = 8.90193e-014
N = 551         mean(abs((rn-tn)) = 8.74037e-014
N = 561         mean(abs((rn-tn)) = 8.58457e-014
N = 571         mean(abs((rn-tn)) = 8.43423e-014
N = 581         mean(abs((rn-tn)) = 8.28906e-014
N = 591         mean(abs((rn-tn)) = 8.1488e-014
N = 601         mean(abs((rn-tn)) = 8.01322e-014
N = 611         mean(abs((rn-tn)) = 7.88207e-014
N = 621         mean(abs((rn-tn)) = 7.75514e-014
N = 631         mean(abs((rn-tn)) = 7.63224e-014
N = 641         mean(abs((rn-tn)) = 7.51317e-014
N = 651         mean(abs((rn-tn)) = 7.39776e-014
N = 661         mean(abs((rn-tn)) = 7.28584e-014
N = 671         mean(abs((rn-tn)) = 7.17726e-014
N = 681         mean(abs((rn-tn)) = 7.07187e-014
N = 691         mean(abs((rn-tn)) = 6.96953e-014
N = 701         mean(abs((rn-tn)) = 6.8701e-014
N = 711         mean(abs((rn-tn)) = 6.77348e-014
N = 721         mean(abs((rn-tn)) = 6.67953e-014
N = 731         mean(abs((rn-tn)) = 6.58816e-014
N = 741         mean(abs((rn-tn)) = 6.49925e-014
N = 751         mean(abs((rn-tn)) = 6.41271e-014
N = 761         mean(abs((rn-tn)) = 6.32844e-014
N = 771         mean(abs((rn-tn)) = 6.24636e-014
N = 781         mean(abs((rn-tn)) = 6.16638e-014
N = 791         mean(abs((rn-tn)) = 6.08842e-014
N = 801         mean(abs((rn-tn)) = 6.01241e-014
N = 811         mean(abs((rn-tn)) = 5.93828e-014
N = 821         mean(abs((rn-tn)) = 5.86595e-014
N = 831         mean(abs((rn-tn)) = 5.79536e-014
N = 841         mean(abs((rn-tn)) = 5.72645e-014
N = 851         mean(abs((rn-tn)) = 5.65916e-014
N = 861         mean(abs((rn-tn)) = 5.59343e-014
N = 871         mean(abs((rn-tn)) = 5.52921e-014
N = 881         mean(abs((rn-tn)) = 5.46645e-014
N = 891         mean(abs((rn-tn)) = 5.4051e-014
N = 901         mean(abs((rn-tn)) = 5.34511e-014
N = 911         mean(abs((rn-tn)) = 5.28644e-014
N = 921         mean(abs((rn-tn)) = 5.22904e-014
N = 931         mean(abs((rn-tn)) = 5.17287e-014
N = 941         mean(abs((rn-tn)) = 5.1179e-014
N = 951         mean(abs((rn-tn)) = 5.06408e-014
N = 961         mean(abs((rn-tn)) = 5.01139e-014
N = 971         mean(abs((rn-tn)) = 4.95978e-014
N = 981         mean(abs((rn-tn)) = 4.90922e-014
N = 991         mean(abs((rn-tn)) = 4.85968e-014


Process returned 0 (0x0)   execution time : 0.686 s
Press any key to continue.

你可能感兴趣的:(任意长度FFT算法的C++实现)