Les codes fantastiques : rester dans la moyenne

Magazine
Marque
GNU/Linux Magazine
Numéro
274
Mois de parution
mars 2025
Spécialité(s)


Résumé

Continuons cette série sur les codes fantastiques avec un problème apparemment simple : calculer la moyenne de deux entiers.


Body

Calculer une moyenne entre deux entiers, quoi de plus simple ? Je livre à vos yeux avides une implémentation en Python :

def average(x, y):
    return (x + y) // 2

Époustouflant, n’est-ce pas ? Allez, sur notre lancée, la même chose en C :

unsigned average(unsigned x, unsigned y) {
    return (x + y) / 2;
}

Facile ! Décidément, le contenu de cette rubrique périclite. Testons cette fonction par acquit de conscience : average(5u, 3u) ? 4, OK. average(1234u, 5678u) ? 3456, OK. Allez, un dernier pour la route average(42424242u, 42424242u) ? 2094940594. 2094940594 ?!?

Maiscestbiensûr, 42424242u > (1u << 31), on a un beau dépassement de la capacité d’un entier sur 32 bits, taille d’un entier sur ma machine ! Comment faire ? Une solution naïve serait de faire le calcul sur un entier de taille supérieure, p. ex. (unsigned)(((long)x + y / 2), mais rien dans le standard ne nous garantit que cela existe.

On peut imaginer s’en sortir avec un peu de math :

unsigned average(unsigned x, unsigned y) {
    return x + ((y – x) / 2);
}

Cela marche sur notre dernier exemple, mais échoue si x > y (on obtient 2147483650 pour average(4u, 0u)). On peut cependant ajouter une comparaison, un swap et le tour est joué :

unsigned average(unsigned x, unsigned y) {
    if(x > y) {unsigned t = x; x = y; y = t; }
    return x + ((y – x) / 2);
}

Il existe cependant une solution bien plus amusante et sans branchement à base de manipulation de bits :

unsigned average(unsigned x, unsigned y) {
    return (x & y) + ((x ^ y) >> 1);
}

En effet, le ET logique nous dit, pour chaque bit, s’il y aura propagation de la retenue. Et si c’est le cas, le bit de retenue, qui devrait être déplacé à gauche, puis à droite à cause de la division par deux, est déjà positionné à la bonne place !

Le OU exclusif, quant à lui, effectue une addition bit à bit sans propagation de retenue. On le divise ensuite par deux et on ajoute la retenue, le compte est bon !

Un avantage de cette solution est qu’elle se calcule sans branchement, c’est donc une bonne candidate pour la vectorisation. C’est d’ailleurs la solution générique utilisée par la bibliothèque https://xsimd.readthedocs.io quand il n’existe pas de version matérielle pour cette opération (ce qui est le cas pour les entiers non signés de 8 et 16 bits en SSE, mais pas pour des entiers plus grands).

Et la version signée ? Vous semble-t-elle plus compliquée ?



Article rédigé par

Par le(s) même(s) auteur(s)

C++ : contrôlez votre espérance de vie

Magazine
Marque
MISC
Numéro
141
Mois de parution
septembre 2025
Spécialité(s)
Résumé

Le langage C est un magnifique outil pédagogique pour enseigner le concept de mémoire, puisqu’il laisse la main au développeur pour la gérer. Mais on le sait, cet attrait n’en est pas un quand on parle de sûreté d’exécution, puisque ce langage est connu pour ne pas aider le développeur pour détecter les usages illégaux liés à la mémoire. Le langage Rust a attaqué le problème en rendant explicite le concept de durée de vie. Le langage Safe C++ tente quant à lui d’introduire ce concept en C++. Il y a plus de vingt ans, splint proposait déjà un concept moins ambitieux pour C. Et maintenant certains fous essaient de le porter vers C++, à travers des extensions de Clang. Quelles sont donc toutes ces approches ?

Les listes de lecture

9 article(s) - ajoutée le 01/07/2020
Vous désirez apprendre le langage Python, mais ne savez pas trop par où commencer ? Cette liste de lecture vous permettra de faire vos premiers pas en découvrant l'écosystème de Python et en écrivant de petits scripts.
11 article(s) - ajoutée le 01/07/2020
La base de tout programme effectuant une tâche un tant soit peu complexe est un algorithme, une méthode permettant de manipuler des données pour obtenir un résultat attendu. Dans cette liste, vous pourrez découvrir quelques spécimens d'algorithmes.
10 article(s) - ajoutée le 01/07/2020
À quoi bon se targuer de posséder des pétaoctets de données si l'on est incapable d'analyser ces dernières ? Cette liste vous aidera à "faire parler" vos données.
Plus de listes de lecture