next up previous contents index
Next: Quicksort Up: No Title Previous: Équations de complexité

La transformée de Fourier rapide

         

La FFT, ou transformée de Fourier rapide, est un des quelques algorithmes dont la publication a provoqué une véritable révolution dans le champ technique. Généralement associé aux noms de J.W. Cooley et J.W. Tuckey qui l'ont publié en 1965, cet algorithme de calcul de la transformée de Fourier discrète avait été maintes fois << redécouvert >> depuis Gauss, notamment par Danielson et Lanczos en 1942. La FFT permet de ramener le calcul de la transformée de Fourier discrète de tex2html_wrap_inline6373 à tex2html_wrap_inline6375 opérations ; cette réduction de complexité suffit à faire passer d'impossibles à facilement résolubles nombre de problèmes.

La transformée de Fourier discrète d'un n-uplet de nombres complexes tex2html_wrap_inline6379 est le n-uplet tex2html_wrap_inline6383 défini par

displaymath6367

tex2html_wrap_inline6385 . Notons que tex2html_wrap_inline6387 et que pour n=1, ceci se réduit en tex2html_wrap_inline6391 . La transformée inverse se calcule ainsi :

displaymath6368

Supposons que n=2m et séparons les éléments de a d'indices pairs de ceux d'indices impairs :

eqnarray2610

Alors, en séparant la somme en deux termes regroupant d'une part les p=2j et d'autre part les p=2j+1, et en utilisant l'égalité tex2html_wrap_inline6401 :

eqnarray2620

Ainsi, pour calculer la transformée de Fourier sur n points, il suffit de calculer deux transformées de Fourier sur n/2 points, de faire n multiplications et n additions. Si n est une puissance de 2, cette décomposition peut s'appliquer récursivement, ce qui donne pour équation de complexité : tex2html_wrap_inline6258 . Il en résulte une complexité en tex2html_wrap_inline6415 opérations.

   figure2651
Figure: Arbre des appels de la FFT sur 8 points

La figure gif représente l'arbre des appels de ce calcul récursif pour n=8 points : aux feuilles, la FFT sur 1 point, qui est l'identité. L'ordre dans lequel les tex2html_wrap_inline6419 sont rangés dans les feuilles, de gauche à droite, est << l'inverse binaire >> de p. La fonction bit_rev(h,p) renverse la représentation binaire de n, pour tex2html_wrap_inline6425 ; par exemple, tex2html_wrap_inline6427 ; on utilise l'opérateur dyadique << (non décrit dans ce cours, comme les autres opérateurs dyadiques &, |, ^ et ~) pour calculer tex2html_wrap_inline6429 :

int bit_rev(int h, int p) {
  int y = 0;
  int n = 1 << h;        /* n = 2 puissance h */      
  int r;
  while (h>0) {
    h = h-1;
    n = n/2;
    r = p%2;
    p = p/2;
    if (r == 1) {
      y = n + y;
    }
  }
  return y;
}

On va donc commencer par permuter le n-uplet a pour ranger ses éléments dans cet ordre :

void bit_rev_array(int h, const int a[], int b[]) {
  int p;
  for (p=0; p < 1<<h; p++) {
    b[bit_rev(h,p)] = a[p];
  }
}

Cela va permettre de construire un algorithme itératif, qui parcourt l'arbre des feuilles vers la racine.

En utilisant la périodicité de la transformée de Fourier, et l'égalité tex2html_wrap_inline6435 , on peut réécrire la dernière expression de tex2html_wrap_inline6437 :

displaymath6369

Cette transformation, de la forme tex2html_wrap_inline6439 , est appelée un papillon (en anglais, butterfly) ; on l'appliquera successivement avec tex2html_wrap_inline6441 , tex2html_wrap_inline5449 , tex2html_wrap_inline6445 , ..., tex2html_wrap_inline6447 .

Plutôt que de programmer cette transformation sur des nombres complexes (ce qui est légèrement plus ennuyeux), on va écrire le programme en arithmétique modulo N, où tex2html_wrap_inline6451 , et t est un entier quelconque, en posant tex2html_wrap_inline6455 , qui est une racine n-ème principale de l'unité dans tex2html_wrap_inline6459 ; on a toujours tex2html_wrap_inline6461 . Par exemple, quand t=2 et tex2html_wrap_inline6465 , on a N=257, et tex2html_wrap_inline6469 ; un n-uplet et sa transformée sont :

eqnarray2688

La fonction butterfly modulo N s'écrit :

void butterfly(int a[], int j, int k, int alpha, int N) {
  int u = a[j];
  int v = (alpha * a[k]) % N;
  a[j] = (u+v) % N;
  a[k] = (u-v+N) % N;
}

void fft(int h, int N, int omega, const int a[], int fft_a[]) {
  int n = 1<<h;
  int l;
  bit_rev_array(h, a, fft_a);
  for (l=1; l<=h; l++) {
    int i;
    int alpha = 1;
    int omega_l = expmod(omega, 1<<(h-l),N);
    int m = 1 << l;
    for (i=0; i<m/2; i++) {
      int j;
      for (j=i; j<n; j = j+m) {
        butterfly(fft_a, j, j+m/2, alpha, N);
      }
      alpha = (alpha * omega_l) % N;
    }
  }
}

next up previous contents index
Next: Quicksort Up: No Title Previous: Équations de complexité

Rene Lalement
Mon Sep 30 18:22:54 MET 1996