next up previous contents index
Next: Exponentielle modulaire et cryptographie Up: No Title Previous: Récursivité terminale

Accélération logarithmique

 

C ne disposant pas d'une opération d'exponentiation, il faut la programmer (ou utiliser celle définie dans la librairie mathématique dans le cas des nombres flottants). Le programme suivant calcule tex2html_wrap_inline5178 , pour des entiers x et e avec tex2html_wrap_inline5184 , en accumulant (par multiplication) x dans y, ceci e fois, l'expression tex2html_wrap_inline5192 étant un invariant de boucle :  

int exp(int x, int e) {
  int y = 1;
  while (e != 0) {
    y = y*x;
    e = e-1;
  }
  return y;
}

Chaque itération effectue une transformation tex2html_wrap_inline5194 ; par exemple, le calcul de exp(5,8) effectue les transformations successives suivantes de (y,e) :

eqnarray915

On vérifie l'invariant

displaymath5172

On a donc l'égalité de valeur de cet invariant au début de la boucle (quand y=1) et à la fin de la boucle (quand e=0) :

displaymath5173

On notera que la version récursive équivalente à ce programme itératif n'est pas celle que l'on écrirait directement à partir de la définition par récurrence de la fonction puissance, mais est la suivante (la boucle du while modifiant les variables y et e, la fonction récursive doit prendre ces valeurs en argument) :

int exp_rec_aux(int x, int y, int e) {
  if (e == 0) {
    return y;
  } else {
    return exp_rec_aux(x, y*x, e-1);
  }
}

int exp_rec(int x, int e) {
  return exp_rec_aux(x,1,e);
}

La fonction exp_rec_aux est une fonction auxiliairegif qui ne sera appelée que par exp_rec.

Pour les trois programmes précédents, le nombre d'itérations ou d'appels récursifs est l'entier e. Il est possible d'accélérer significativement ce calcul en ramenant e à au plus tex2html_wrap_inline5206 , grâce à la propriété suivante :

eqnarray928

Par exemple, tex2html_wrap_inline5208 en quatre multiplications au lieu de 9. On obtient la définition    

int exp_fastrec_aux(int x, int y, int e) {
  if (e == 0) {
    return y;
  } else if (e % 2 == 1) {
    return exp_fastrec_aux(x, x*y, e-1);
  } else {
    return exp_fastrec_aux(x*x, y, e/2);
  }
}

La version itérative s'écrit facilement à partir de cette version récursive terminale, en remplaçant la liste des arguments des appels récursifs par des affectations :

int exp_fastiter(int x, int e) {
  int y = 1;
  while (e!=0) {
    if (e%2 == 1) {
      y = x*y;
      e = e-1;
    } else {
      x = x*x;
      e = e/2;
    }
  }
  return y;
}

Le cas bénéficiant de la plus forte accélération est celui où l'exposant est une puissance de 2 ; voici la suite des transformations de (x,y,e) pour le calcul de tex2html_wrap_inline5212 (en trois itérations au lieu de 8):

displaymath5174

La situation est moins favorable quand l'exposant n'est pas une puissance de 2 ; le calcul de tex2html_wrap_inline5214 se fait en 5 itérations, soit moins de tex2html_wrap_inline5216 :

eqnarray940

Cet algorithme est décrit dans le Chandah Sutra d'Acharya Pingala (écrit avant 200 ans avant J.C.).


next up previous contents index
Next: Exponentielle modulaire et cryptographie Up: No Title Previous: Récursivité terminale

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