The Fast Fourier Transform

The fast Fourier transform (FFT) is an algorithm which can take the discrete Fourier transform of a array of size n = 2N in Θ(n ln(n)) time. This algorithm is generally performed in place and this implementation continues in that tradition. Two implementations are provided:

  • The first implementation, FFT.basic.h, emphasizes the algorithm; consequently, to simplify the presentation, it allocates additional memory when dividing the vector into even and odd entries and explicit recursion is used, and
  • The second implementation, FFT.array.h, demonstrates how the FFT algorithm can be performed with only O(1) additional memory and without recursive function calls. Reference, Maple 8, Waterloo Maple Inc., Waterloo, Ontario.

The website Fastest Fourier Transform in the West (see wikipedia for a summary) provides the fastest portable free software implementation of the FFT.

Some comments on the code:

The value π is found using double const PI = 4.0*std::atan( 1.0 ); The inverse tangent function of 1 returns π/4 and and multiplication by a power of 2 does not affect the relative error of a floating point number: in this case, multiplication by four simply adds two to the exponent.

The testing function applies the fast Fourier transform to the vector (2, 2, 0, 0, 0, 0, 0, 0)T. It prints the vector, the fast Fourier transform of the vector, and the inverse fast Fourier transform of that result. The output is

(1,0) (1,0) (0,0) (0,0) (0,0) (0,0) (0,0) (0,0) 
(2,0) (1.70711,-0.707107) (1,-1) (0.292893,-0.707107) (0,0) (0.292893,0.707107) (1,1) (1.70711,0.707107) 
(1,0) (1,0) (0,0) (0,0) (0,0) (0,0) (0,0) (0,0) 

You will note that 1/√2 ≈ 0.707107, and 1 − 1/√2 ≈ 0.292893 .

The function printing the complex array will print 0 in place of either component being less than 10-15. This is to make aid in the visualization of the result.

The Discrete Fourier Transform

The discrete Fourier transform maps a vector from the space domain to the complex frequency domain. To describe this, recall that a vector of n dimensions represents coordinates in space: the basis vectors are the n unit vectors (1, 0, 0, ···), (0, 1, 0, ···), etc. These are shown in Figure 1.

Figure 1. The unit basis vectors for a vector of dimension 8.

While these unit vectors are exceelent for representing the specific location of a vector, they do not suggest any periodicity. The discrete Fourier transforms is a linear transformation from a basis of unit vectors to a basis of vectors which are capture the periodic behaviour of the unit vector: if the copies of the vector were laid end-to-end, what periodicity would there be in the patterns and what are the periods thereof.

Figure 2. The basis vectors of the frequency space of dimension 8.

template <typename T> class complex<T>

This code uses the STL complex class which has a constructor which takes the real and imaginary parts as arguments. The following functions are friends of the class and for the argument z = a + jb:

double abs(z)|z| = √(a2 + b2)
double arg(z)atan2(ℑ(z), ℜ(z)) = atan2(b, a)
complex conj(z)z* = ajb
double imag(z)ℑ(z) = b
double norm(z)|z|2 = a2 + b2
complex polar(r, θ) re
double real(z)ℜ(z) = a
complex exp(z)ez
complex log(z)ln(z)
complex pow(w, z)wz
complex sqrt(z)z
complex sin(z)sin(z)
complex cos(z)cos(z)
complex sinh(z)sinh(z)
complex cosh(z)cosh(z)

A complex number a + jb is printed as the ordered pair (a,b).

Determining Powers of Two

The assertion assert( n > 0 && (n & (~n + 1)) == n ); checks to ensure that the argument n is both positive and a power of two. The operation n & (~n + 1) selects the least significant one in the integer. If the least significant one is also the most significant one, then the bitwise and will return that value; otherwise, the result will not equal the original value n. This is shown in Figure 3 with both a power of two (64) and a number which is not a power of two (84).

Figure 3. Selecting the least significant one (1) bit in a binary number.