Calculer une factorielle par la technique Duff (Duff's Device)

Alors qu'il était chez Lucasfilms, Tom Duff a développé une technique de déroulement de boucle (Loop Unrolling) quelque peu surprenante. En effet, constatant qu'une sélective (un switch) n'est en fait qu'un goto déguisé, il a montré qu'il était possible d'entrelacer une sélective avec une structure de contrôle répétitive pour réduire le nombre de tests de la condition de poursuite de cette dernière, tout en traitant les opérations résiduelles comme un cas dégénéré, résolu en sautant en plein coeur de la dversion déroulée de la répétitive en question.

Illustrons sa technique avec un exemple simple, soit celui du calcul de la factorielle d'un entier. Le code suit :

#include <iostream>
double factorielle(int n) noexcept {
   double cumul = 1.0;
   int i = 1;
   if (n == 0)
      return 1;
   else if (n % 8 == 0)
      cumul *= n--;
   switch (8 - n % 8) {
      do {
   case 0: cumul *= i++;
   case 1: cumul *= i++;
   case 2: cumul *= i++;
   case 3: cumul *= i++;
   case 4: cumul *= i++;
   case 5: cumul *= i++;
   case 6: cumul *= i++;
   case 7: cumul *= i++;
      } while (i <= n);
   }
   return cumul;
}
int main() {
   using namespace std;
   enum { N = 10 };
   for (int i = 0; i <= N; ++i)
      cout << i << "! == " << factorielle(i) << endl;
}

Croyez-le ou non, à l'exécution, nous obtenons ce qui suit :

0! == 1
1! == 1
2! == 2
3! == 6
4! == 24
5! == 120
6! == 720
7! == 5040
8! == 40320
9! == 362880
10! == 3.6288e+06

Récapitulons rapidement :

Variante dégénérée

Une autre variante tout aussi horrible est la suivante, qui ne sert à rien mais montre l'absence de structure réelle d'une sélective, est la suivante (je ne me souviens plus de qui je l'ai prise, tristement, mais j'ai quelques amis peu fréquentables alors...) :

void foo(int a, int b, int c, int d, int e, int f);
void bar(int x) {
   switch (x)
      foo(({case 0:; 0; }),
          ({case 1:; 1; }),
          ({case 2:; 2; }),
          ({case 3:; 3; }),
          ({case 4:; 4; }),
          ({case 5:; 5; }));
}

Je vous laisse méditer sur la chose...

Lectures complémentaires

Pour enrichir votre compréhension de ce sujet, quelques liens.


Valid XHTML 1.0 Transitional

CSS Valide !