next up previous contents
suivant: Polynômes monter: Corrigés des programmes précédent: Tri par insertion   Table des matières

Transformée de Fourier

fourier.c


#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<math.h>
#include"complexe.h"
#include"fourier.h"
#include"linkedList.h"

/*------------------------------------------*/

/*
  Retourne les racines n-eme de c, O(n)
 */

linkedList* racinesComplexe(complexe c, unsigned long n)
{
  linkedList* l = linkedListCreate();
  pComplexe p;
  unsigned long i;
  for(i = 0 ; i < n ; i++)
    {
      p = (pComplexe)malloc(sizeof(complexe));
      if (p == NULL)
	exit(1);
      *p = makeExpComplexe(pow(c.mod, 1./n), (c.arg/n) + (i)*2*M_PI/n);
      linkedListAppend(l, p);
    }
  return l;
}

/*------------------------------------------*/

/*
  Retourne les racines n-eme de 1, O(n)
 */

linkedList* uniteRacinesComplexe(unsigned long n)
{
  return racinesComplexe(makeAffComplexe(1.0, 0.0), n);
}

/*------------------------------------------*/

/*
  Donne l'image de x par polynome. Les coefficients du polynome sont  
  ranges par ordre de degre croissant. O(n).
 */

complexe horner(link* polynome, complexe x)
{
  if (polynome == NULL)
    return makeAffComplexe(0.0, 0.0);
  return addComplexe(*(pComplexe)polynome->data, 
		     multComplexe(x, 
				  horner(polynome->next,
						 x)));
}

/*------------------------------------------*/

/*
  Detruit complexe pointe par p.
*/

void deallocateComplexe(void* p)
{
  free((pComplexe)p);
}

/*------------------------------------------*/

/*
  Retourne la transformee discrete de Fourier du vecteur l, 
  version iterative en O(n^2)
 */

linkedList* transformeeFourierIt(linkedList* polynome)
{
  linkedList* FT = linkedListCreate();
  linkedList* W_n = uniteRacinesComplexe(linkedListGetSize(polynome));
  void* evaluate(void* w)
    {
      pComplexe p = (pComplexe)malloc(sizeof(complexe));
      if (p == NULL)
	exit(0);
      *p = horner(linkedListGetFirst(polynome),  
			  *(pComplexe)w);
      return p;
    }
  FT = linkedListMap(W_n, evaluate);
  linkedListDestroy(W_n, deallocateComplexe);
  return FT;
}

/*------------------------------------------*/

/*
  Ne fait rien...
*/

void doNothing(void* w)
{
}

/*------------------------------------------*/

/*
  Retourne la transformee discrete de Fourier du vecteur l, 
  version recursive en O(n.log n)
 */

linkedList* FFT(linkedList* polynome)
{
  // creation des listes
  linkedList* FT = linkedListCreate(); // resultat
  linkedList* odd =  linkedListCreate(); // coefficients d'indice pair
  linkedList* even =  linkedListCreate();// coefficients d'indice impair
  linkedList* a_0 =  linkedListCreate(); // TF de odd
  linkedList* a_1 =  linkedListCreate(); // TF de even
  link* l; // pour parcourir FT
  complexe w = makeAffComplexe(1.0, 0.0);
  complexe c = makeExpComplexe(1.0, 2*M_PI/linkedListGetSize(polynome));
  int isEven = 1;
  // cas de base
  if (linkedListGetSize(polynome) == 1)
    {
      linkedListAppend(FT, 
		       copyComplexe(*(pComplexe)
				    (linkedListGetFirst(polynome)->data)));
      return FT;
    }
  // autres cas
  void split(void* coeff)
    {
      if (isEven)
	linkedListAppend(even, coeff);
      else
	linkedListAppend(odd, coeff);
      isEven = !isEven;
    }
  // separation de polynome
  linkedListApply(polynome, split);
  // appels recursifs
  a_0 = FFT(even);
  a_1 = FFT(odd);
  void evenValues(void* v)
    {
      linkedListAppend(FT, copyComplexe(*(pComplexe)v));
    }
  // ajout dans FT des valeurs de a^[0]
  linkedListApply(a_0, evenValues);
  linkedListApply(a_0, evenValues);
  l = linkedListGetFirst(FT);
  void oddValues(void* v)
    {
      pComplexe ft = (pComplexe)(l->data);
      *ft = addComplexe(*ft, multComplexe(w, *(pComplexe)v));
      w = multComplexe(c, w);
      l = l->next;
    }
  // ajout dans FT des w_n^p * a^[1]_p
  linkedListApply(a_1, oddValues);
  linkedListApply(a_1, oddValues);
  // liberation de la memoire
  linkedListDestroy(odd, doNothing);
  linkedListDestroy(even, doNothing);
  linkedListDestroy(a_0, deallocateComplexe);
  linkedListDestroy(a_1, deallocateComplexe);
  return FT;
}

/*------------------------------------------*/

/*
  Retourne la transformee discrete de Fourier du vecteur l, 
  version recursive en O(n.log n)
 */

linkedList* inverseFFT(linkedList* polynome)
{
  linkedList* FT = linkedListCreate();
  linkedList* odd =  linkedListCreate();
  linkedList* even =  linkedListCreate();
  linkedList* a_0 =  linkedListCreate();
  linkedList* a_1 =  linkedListCreate();
  link* l;
  complexe w = makeAffComplexe(1.0, 0.0);
  complexe c = makeExpComplexe(1.0, -2.*M_PI/linkedListGetSize(polynome));
  int isEven = 1;
  if (linkedListGetSize(polynome) == 1)
    {
      linkedListAppend(FT, 
		       copyComplexe(*(pComplexe)
				    (linkedListGetFirst(polynome)->data)));
      return FT;
    }
  void split(void* coeff)
    {
      if (isEven)
	linkedListAppend(even, coeff);
      else
	linkedListAppend(odd, coeff);
      isEven = !isEven;
    }
  linkedListApply(polynome, split);
  a_0 = inverseFFT(even);
  a_1 = inverseFFT(odd);
  void evenValues(void* v)
    {
      linkedListAppend(FT, copyComplexe(*(pComplexe)v));
    }
  linkedListApply(a_0, evenValues);
  linkedListApply(a_0, evenValues);
  l = linkedListGetFirst(FT);
  void oddValues(void* v)
    {
      pComplexe ft = (pComplexe)(l->data);
      complexe value  = multComplexe(w, *(pComplexe)v);
      value = multReelComplexe(1./2., addComplexe(*ft, value));
      *ft = value;       
      w = multComplexe(c, w);
      l = l->next;
    }
  linkedListApply(a_1, oddValues);
  linkedListApply(a_1, oddValues);
  void doNothing(void* w){}
  linkedListDestroy(odd, doNothing);
  linkedListDestroy(even, doNothing);
  void deallocateComplexe(void* p)
    {
      free((pComplexe)p);
    }
  linkedListDestroy(a_0, deallocateComplexe);
  linkedListDestroy(a_1, deallocateComplexe);
  return FT;
}

/*------------------------------------------*/

/*
  Retourne la transformee discrete de Fourier inverse 
  du vecteur l, version iterative en O(n^2)
 */

linkedList* transformeeInverseFourierIt(linkedList* polynome)
{
  linkedList* FT = linkedListCreate();
  int n = linkedListGetSize(polynome);
  linkedList* W_n = uniteRacinesComplexe(n);
  void conjugue(void* w)
    {
      *(pComplexe)w = conjugueComplexe(*(pComplexe)w);
    }
  linkedListApply(W_n, conjugue);
  void* evaluate(void* w)
    {
      pComplexe p = (pComplexe)malloc(sizeof(complexe));
      if (p == NULL)
	exit(0);
      *p = horner(linkedListGetFirst(polynome), 
			  *(pComplexe)w);
      return p;
    }
  FT = linkedListMap(W_n, evaluate);
  void divise(void* w)
    {
      *(pComplexe)w = multReelComplexe(1./n, *(pComplexe)w);
    }
  linkedListApply(FT, divise);
  void deallocateComplexe(void* p)
    {
      free((pComplexe)p);
    }
  linkedListDestroy(W_n, deallocateComplexe);
  return FT;
}

/*------------------------------------------*/

linkedList* simpleList(int n)
{
  if (n == 0)
    return linkedListCreate();
  linkedList* l =  simpleList(n - 1);
  linkedListAppend(l, copyComplexe(makeAffComplexe(n, 0.0)));
  return l;
}

/*------------------------------------------*/
/*
int main()
{
  int k = 512;
  void printC(void* v)
    {
      printAffComplexe(*((pComplexe)v));
      printf("\n");
    }
  printf("liste\n");
  linkedListApply(simpleList(k), 
		  printC); 
  printf("FFT de liste\n");
  linkedListApply(FFT(simpleList(k)), 
		  printC); 
  printf("FFT-1 o FFT de liste\n");
  linkedListApply(inverseFFT(FFT(simpleList(k))),
		  printC);
  return 0;
}
*/



klaus 2010-08-05