next up previous contents
suivant: Arbres binaires et -aires monter: Corrigés des programmes précédent: Transformée de Fourier   Table des matières

Polynômes

polynomes.c


#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<math.h>
#include"polynomes.h"

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

/*
Retourne un polynome vide.
 */

linkedList* makePolynome()
{
  return linkedListCreate();
}

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

/*
  Alloue dynamiquement un emplacement pour une variable de type 
  double, y affecte d et retourne cette adresse.
 */

double* makeDouble(double d)
{
  double* p = (double*)malloc(sizeof(double));
  if (p == NULL)
    exit(0);
  *p = (double)d;
  return p;	
}

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

/*
  Alloue dynamiquement un emplacement pour une variable de type 
  double, y affecte d et retourne cette adresse.
 */

void* makeDoubleWithVoid(void* v)
{
  return makeDouble(*(double*)v);
}

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

/*
  Desalloue une variable de type double.
 */

void destroyDouble(void* v)
{
  free((double*)v);
}

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

/*
  Retourne une copie de l, copie aussi les coefficients.
*/

linkedList* copyPolynome(linkedList* l)
{
  return linkedListMap(l, makeDoubleWithVoid);
}

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

/*
  Detruit le polynome l et ses coefficients.
 */

void destroyPolynome(linkedList* l)
{
  linkedListDestroy(l, destroyDouble);
}

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

/*
  Affiche le monome coeff * x^degre proprement, firstPrinted 
  est vrai si et seulement si ce monome est le premier affiche 
  dans le polynome.
 */

int printMonome(double coeff, int degre, int firstPrinted)
{
  if (coeff != 0.0)
    {
      if (firstPrinted && coeff > 0.0)
	  printf(" + ");
      if(coeff<0.0)
	printf(" - ");
      printf("%4.2lf", (coeff>0)?coeff:-coeff);
      if(degre > 0)
	printf("x");
      if(degre > 1)
	printf("^");
      if(degre > 1)
	printf("%d", degre);
      return 1;
    }
  return 0;
}

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

/*
  Affiche polynome le plus proprement possible.
*/

void printPolynome(linkedList* polynome)
{
  int degre = 0, firstPrinted = 0;
  void f(void* coeff)
    {
      if (printMonome(*(double*)coeff, degre, firstPrinted))
	firstPrinted = 1;
      degre++;
    }
  linkedListApply(polynome, f);
  printf("\n");
}

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

/*
  Supprime les O non significatifs à la fin du polynôme.
 */

void skipZerosPolynome(linkedList *l)
{
}

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

/*
  Retourne le degre de l.
 */

int degreePolynome(linkedList *l)
{
  int n;
  skipZerosPolynome(l);
  n = linkedListGetSize(l);
  if(n != 1)
    return n;
  return (*(double*)linkedListGetFirst(l)->data != 0) - 1;
}

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

/*
  Ajoute un monome de coefficient coeff a la fin du polynome, faisant 
  ainsi croutre son degre de 1.
*/

void appendCoeffPolynome(linkedList* polynome, double coeff)
{
  double* p = malloc(sizeof(double));
  if (p == NULL)
    exit(0);
  *p = coeff;
  linkedListAppend(polynome, p);
}

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

/*
  Cree et retourne le polynome de degre n-1 dont les 
  coefficients sont passes dans le tableau d.
 */

linkedList* makeArrayPolynome(double* d, int n)
{
  linkedList* l = makePolynome();
  int i;
  for(i = 0 ; i < n ; i++)
    appendCoeffPolynome(l, *(d + i));
  return l;
}

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

/*
  Retourne le polynome nul.
*/

linkedList* zeroPolynome()
{
  linkedList* l = makePolynome();
  appendCoeffPolynome(l, 0.0);
  return l;
}

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

/*
  Retourne le polynome unite.
*/

linkedList* unitPolynome()
{
  linkedList* l = makePolynome();
  appendCoeffPolynome(l, 1.0);
  return l;
}

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

/*
  Retourne le polynome 
  0 + X + 2X^2 + 3X^3 + ... + iX^i + ... + nX^n
*/

linkedList* simpleListPolynome(int n)
{
  linkedList* l;
  if (n == 0)
    return zeroPolynome();
  l = simpleListPolynome(n - 1);
  appendCoeffPolynome(l, n);
  return l;
}

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

/*
  Ajoute la constante d au polynome l.
*/

void addRealPolynome(linkedList* l, double d)
{
  link* lnk = linkedListGetFirst(l);
  if (lnk != NULL)
    *(double*)lnk->data += d;
  else
    appendCoeffPolynome(l, d);
}

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

/*
  Multiplie le polynome l par le reel d.
*/

void multRealPolynome(linkedList* l, double d)
{
  void multiplyDouble(void* v)
    {
      *(double*)v *= d;
    }
  linkedListApply(l, multiplyDouble);
}

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

/*
  Multiplie le polynome l par X^n
*/

void multXNPolynome(linkedList* l, int n)
{
  if (n > 0)
    {
      linkedListPush(l, makeDouble(0.0));
      multXNPolynome(l, n - 1);
    }
}

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

/*
  Multiplie le polynome l par coeff*X^exp 
*/

void multMonomePolynome(linkedList* l, double coeff, int exp)
{
  multRealPolynome(l, coeff);
  multXNPolynome(l, exp);
}

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

/*
  Additionne deux à deux tous les maillons des deux listes la
  et lb. Concatene le resultat a la liste result.
*/

void addMaillons(link* la, link* lb, linkedList* result)
{
  if (la != NULL && lb != NULL)
    {
      appendCoeffPolynome(result, *(double*)la->data
			  + *(double*)lb->data);
      addMaillons(la->next, lb->next, result);
    }
  else
    {
      if (la != NULL)
	{
	  appendCoeffPolynome(result, *(double*)la->data);
	  addMaillons(la->next, NULL, result);	      
	}
      if (lb != NULL)
	{
	  appendCoeffPolynome(result, *(double*)lb->data);
	  addMaillons(NULL, lb->next, result);	      
	}
    }      
}

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

/*
  Additione les deux polynomes a et b, retourne cette somme.
*/

linkedList* addPolynome(linkedList* a, linkedList* b)
{
  linkedList* result = makePolynome();
  addMaillons(linkedListGetFirst(a), 
	      linkedListGetFirst(b), 
	      result);
  return result;
}

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

/*
  Multiplie a et b avec la recurrence 
  (a_0 + a_1X + ... + a_nX^n)Q(X)
  = a_0 * Q(X) + X * (a_1 + a_2 X...+ a_n X^(n-1)) * Q(X)
*/

linkedList* slowMultPolynome(linkedList* a, linkedList* b)
{
  linkedList* temp1 = NULL;
  linkedList* res = zeroPolynome();
  int n = 0;
  void auxFunction(void* v)
    {
      linkedList* temp2 = copyPolynome(b);
      multMonomePolynome(temp2, *(double*)v, n);
      temp1 = addPolynome(res, temp2);
      destroyPolynome(res);
      destroyPolynome(temp2);
      res = temp1;
      n++;
    }
  linkedListApply(a, auxFunction);
  return res;
}

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

/*
  Fonction auxiliaire pour le sous-programme ci-dessous.
*/

void multMaillons(link* la, link* lb, linkedList* result)
{
  pComplexe p;
  if (la != NULL)
    {
      p = copyComplexe(
		       multComplexe(
				    *(pComplexe)la->data,
				    *(pComplexe)lb->data));
      linkedListAppend(result, p);
      multMaillons(la->next, lb->next, result);
    }
}


/*--------------------------------------------------*/
/*
  Multiplie entre eux tous les coefficients (complexes) des monomes de 
  meme degre, par exemple : 
  (1 + 2X + 4X^2) et (3 + X - 2X^2) donnent
  (1 * 3) + (2 * 1)X + (4 * -2)X^2
  a et b sont necessairement de meme degre.
*/

linkedList* multMonomesPolynome(linkedList* a, linkedList* b)
{
  linkedList* l = makePolynome();
  multMaillons(linkedListGetFirst(a), 
	      linkedListGetFirst(b),
	      l);
  return l;
}

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

/*
  Convertit un double en pointeur sur complexe.
 */

void* complexOfDouble(void* v)
{
  return copyComplexe(makeAffComplexe(*(double*)v, 0.0));
}

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

/*
  Convertit un complexe en double, supprime 
  la partie imaginaire.
*/

void* doubleOfComplexe(void* v)
{
  return makeDouble(reComplexe(*(pComplexe)v));
}

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

/*
  Detruit un nombre complexe.
*/

void destroyComplexe(void* v)
{
  free((pComplexe)v);
}

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

/*
  Retourne la premier puisance de 2 superieure ou egal a x.
*/

int puiss2UpperThan(int x)
{
  int k = 2;
  while(k < x)
    k *= 2;
  return k;
}

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

/*
  Ajoute des zeros non significatifs a la fin de l de sorte 
  que sa taille devienne k.  
 */

void resizeList(linkedList* l, int k)
{
  while(linkedListGetSize(l) < k)
    linkedListAppend(l, 
		     copyComplexe(makeAffComplexe(0.0, 0.0)));
}

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

/*
  Modifie les tailles des deux listes de sorte 
  qu'on puisse leur appliquer une FFT
 */

void calibrateLists(linkedList* l1, linkedList* l2)
{
  int k;
  int length = linkedListGetSize(l1) + 
    linkedListGetSize(l2) - 1;
  k = puiss2UpperThan(length);
  resizeList(l1, k);
  resizeList(l2, k); 
}

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

/*
  Multiple a et b en passant par une transformee de fourier.
 */

linkedList* multPolynome(linkedList* a, linkedList* b)
{
  linkedList *ca, *cb, *ffta, *fftb, *prodab, *resComplexe, *res;
  ca = linkedListMap(a, complexOfDouble);
  cb = linkedListMap(a, complexOfDouble);
  calibrateLists(ca, cb);
  ffta = FFT(ca);
  fftb = FFT(cb);
  prodab = multMonomesPolynome(ffta, fftb);
  resComplexe = inverseFFT(prodab);
  res = linkedListMap(resComplexe, doubleOfComplexe);
  linkedListDestroy(ca, destroyComplexe);
  linkedListDestroy(cb, destroyComplexe);
  linkedListDestroy(ffta, destroyComplexe);
  linkedListDestroy(fftb, destroyComplexe);
  linkedListDestroy(prodab, destroyComplexe);
  linkedListDestroy(resComplexe, destroyComplexe);
  return res;
}

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

/*
  Evalue le polynome l en x avec la methode de Horner.
 */

double hornerLink(link* lnk, double x)
{
  if (lnk == NULL)
    return 0.0;
  return *(double*)lnk->data + 
    x*hornerLink(lnk->next, x);
}

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

/*
  Evalue le polynome l en x avec la methode de Horner.
 */

double evaluatePolynome(linkedList *l, double x)
{
  return hornerLink(linkedListGetFirst(l), x);
}

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

int main()
{
  linkedList *l = simpleListPolynome(10000);
  //makeArrayPolynome(d, 5);
  linkedList *m, *n, *p;
  printf("multiplication\n");
  m = slowMultPolynome(l, l);
  printf("done\n");
  //printPolynome(m);
  printf("multiplication\n");
  n = multPolynome(l, l);
  printf("done\n");
  //printPolynome(m);
  multRealPolynome(n, -1);
  p = addPolynome(m, n);
  printf("test : %lf\n", evaluatePolynome(p, 1.0));
  destroyPolynome(l);
  destroyPolynome(m );
  destroyPolynome(n );
  return 0;
}



klaus 2010-08-05