informatique (MP2I/MPI) · Chapitre 14 · Application directe du cours
Le masque qui déborde
Exploration exhaustive et retour sur trace · niveau 2
Énoncé
L'énumération par bits porte la précondition . Que se passe-t-il exactement pour et ? Le compilateur prévient-il ?
for (int masque = 0; masque < (1 << n); masque = masque + 1) { /* ... */ }Corrigé
Les deux cas sont des comportements indéfinis au sens de la norme C99 : décaler un int de rangs ou plus dépasse la largeur du type. La norme n'exige rien, et le compilateur ne signale rien. Il faut donc mesurer ce que produit la machine devant soi. Compilé avec gcc -Wall -Wextra -std=c99, aucun avertissement n'est émis, et l'exécution donne :
(1 << n) | tours de boucle | |
|---|---|---|
| 29 | ||
| 30 | ||
| 31 | 0 | |
| 32 | 1 |
Pour , le bit de poids fort est le bit de signe : vaut INT_MIN, la condition masque < (1 << n) est fausse d'emblée et la boucle ne s'exécute pas une seule fois. Pour , le décalage a été fait modulo : vaut , et la boucle ne visite que le sous-ensemble vide.
Le piège est complet : aucune erreur de compilation, aucune erreur d'exécution, aucun résultat — et un programme qui rend « aucune solution » sur les instances de taille alors qu'il en trouvait à . C'est le dépassement silencieux du chapitre chap:langage-c, à un endroit où on ne le cherche pas.
La parade : écrire la borne sur un type assez large, et documenter la limite.
/* Énumère les 2^n sous-ensembles. Précondition : 0 <= n <= 62. */
assert(0 <= n && n <= 62);
for (unsigned long long masque = 0; masque < (1ULL << n); masque = masque + 1) {
/* ... */
}
Mesuré : 1ULL << 31 vaut et 1ULL << 32 vaut . Cela dit, à la boucle ne finira jamais : la vraie limite reste celle de l'exercice précédent.
Exercices semblables
- Trois seuils, et ce qu'une machine mille fois plus rapide y change corrigé
- La ligne qu'on oublie : combien de solutions produit-elle ? corrigé
- Compter les chemins hamiltoniens, avec la grille complète corrigé
- Le même élagage, dix fois plus vite corrigé
- Problème — Le sudoku : la même exploration, deux ordres de choix corrigé