Pour commencer ce livre, nous devons d'abord parler des opérations logiques : que sont-elles, à quoi servent-elles ? Ces opérations logiques travaillent sur des suites de bits d'une longueur fixe, des nombres pour simplifier. Ces opérations modifient directement l'écriture binaire d'un nombre, la suite de bits correspondante. Il en existe de deux types, les instructions bit à bit et les instructions de décalage, que nous allons voir l'une après l'autre. Pour les connaisseurs, nous allons voir quelques opérations iconiques, comme les décalages et les rotations, mais aussi comment concevoir une unité de calcul 2 à 3 bits, les masques et quelques autres opérations.
Les opérations bit à bit proprement dit.
Les instructions logiques les plus courantes sont au nombre de 4 : le NON, le ET, le OU, et le XOR.
Toutes ces instructions vont travailler sur des bits individuels d'un ou de deux nombres, et leur faire subir une opération bien précise.
Cette opération prend deux bits (un seul pour le NON) et donne un résultat codé sur un bit.
Le fonctionnement de cette opération peut être définie par ce qu'elle fait sur un bit, son comportement étant résumé dans un tableau qu'on appelle la table de vérité. Leur résultat n'est pas vraiment interprétable mathématiquement, ou alors avec un sens vraiment idiosyncratique.
La plus simple est clairement l'opération NOT, qui inverse tous les bits d'un nombre.
Mais il est aussi possible de prendre deux nombres, de faire un ET/OU/XOR entre les bits de même poids, et de renvoyer le tout en guise de résultat.
Formellement, ce sont les seuls types d'opérations bits à bit : l'inversion des bits d'un nombre, un ET entre deux nombres, un OU entre deux nombres, et un XOR entre deux nombres (avec leurs dérivées, tel un NAND ou un NOR).
L’opération d'inversion (NOT).
L'inversion bit à bit va inverser tous les bits d'un nombre : les 0 deviennent des 1, et les 1 deviennent des 0. Exemple : le nombre 01110011 va devenir 10001100.
La table de vérité du NOT est celle-ci :
Le NOT d'un bit et/ou d'un nombre sera noté comme ceci : formula_1.
On peut remarquer qu'inverser deux fois de suite un bit redonne le bit initial. Autrement dit, formula_2.
Le résultat de cette opération dépend de l'encodage du nombre. Plus précisément, l'interprétation du résultat n'est pas la même selon que le nombre inversé soit non-signé, en complément à 1, en complément à 2, etc.
Le dernier résultat est facile à comprendre. On sait que la somme formula_6 donne un nombre de n bits dont tous les bits sont à 1. Un tel nombre vaut exactement, par définition, formula_7. On a donc formula_8, ce qui donne le résultat précédent avec quelques manipulations algébriques triviales. L'image de droite montre ce que fait l'opérateur NOT sur un entier en complément à deux.
L'opération ET (AND).
Vient ensuite le ET bit à bit, aussi appelé AND bit à bit. Celui-ci prend deux nombres en opérandes et donne un nombre comme résultat. Sur ces deux nombres, il va prendre les bits qui sont à la même place et va effectuer dessus une petite opération qui donnera le bit du résultat. Cette opération est un simple AND binaire. Ce AND binaire prend deux bits, A et B, et fonctionne comme ceci :
Cet opérateur AND bit à bit est symbolisé comme ceci : formula_9. Le symbole de l'opérateur ET ressemble à celui d'un produit car l'opérateur donne effectivement le résultat de la multiplication bit à bit.
Exemple : formula_10
L'instruction AND bit à bit est commutative : formula_11
Elle est aussi associative : formula_12
Elle est aussi distributive avec le OR bit à bit : formula_13
On peut aussi remarquer qu'elle dispose de la propriété d'idempotence : formula_14
Petite remarque : formula_15
De plus, formula_16
L'opération OU (OR).
Vient ensuite le OR bit à bit. Il fonctionne comme le AND bit à bit sauf qu'il effectue un OR binaire entre les bits du nombre. Ce OR binaire prend deux bits, A et B, et fonctionne comme ceci :
Cet opérateur OR bit à bit est symbolisé comme ceci : formula_17. Pour éviter toute ambiguïté en présence d'addition, nous utiliserons parfois le symbole formula_18 dans la suite du cours.
Exemple : formula_19
L'opérateur OR est commutatif : formula_20
Il est aussi associatif : formula_21
Il est aussi distributif avec le AND bit à bit : formula_22
On peut aussi remarquer qu'il dispose de la propriété d'idempotence : formula_23
Petite remarque : formula_24
L'opération OU exclusif (XOR).
Vient ensuite le OU exclusif bit à bit, appelé XOR en anglais ("eXclusive OR"). Il fonctionne comme le AND et le OR bit à bit sauf qu'il effectue un XOR binaire entre les bits du nombre. Ce XOR binaire prend deux bits, A et B, et fonctionne comme ceci :
Le résultat est 0 quand les deux bits sont égaux, et 1 quand les deux bits sont différents.
Cet opérateur XOR bit à bit est symbolisé comme ceci : formula_25 comme une addition bit à bit sans retenue.
Exemple : formula_26
L'opérateur XOR est commutatif : formula_27
Il est aussi associatif : formula_28
Petite remarque : formula_29
Autre remarque : formula_30
Les décalages et rotations.
À côté des opérations précédentes, on trouve les opérations de décalage, qui décalent un nombre binaire de un ou plusieurs rangs vers la gauche ou la droite. A priori, cette opération n'a rien de compliqué, à un détail près : lorsqu'on décale un nombre, certains bits sont inconnus, ce qui laisse des vides qu'il faut combler. Pour résoudre ce petit problème, il existe diverses solutions, qui donnent naissance à plusieurs types de décalages : les décalages logiques, les décalages arithmétiques et les rotations.
Les décalages logiques.
L'idée la plus immédiate serait de remplir ces vides avec des zéros, ce qui donne un décalage logique. Pour un décalage vers la gauche, l'opération similaire en décimal serait d'ajouter des zéros à la fin d'un nombre, ce qui serait équivalent à multiplier par 10, 100, 1000, bref : par une puissance de 10. Un décalage à droite reviendrait en binaire à décaler la position de la virgule d'un cran vers la gauche et à oublier ce qu'il y a après la virgule, ce qui revient à diviser par une puissance de dix. Cette logique vaut aussi pour le décalage en binaire, si on se rappelle toutefois qu'on doit compter en base 2. Un décalage logique à gauche correspond donc à une multiplication ou division par 2, 4, 8, 16, ..., bref, par une puissance de deux.
L'utilité principale des opérations de décalage est donc qu'elles permettent de faire simplement des multiplications ou divisions par formula_31, pour les entiers non signés. Précisément, un décalage vers la gauche de formula_32 rangs est équivalent à une multiplication par formula_31, alors que le décalage vers la droite qui revient à diviser un nombre entier par formula_31. Cette propriété est souvent utilisée par certains compilateurs, qui préfèrent utiliser des instructions de décalages (qui sont des instructions très rapides) à la place d'instructions de multiplication ou de division qui ont une vitesse qui va de moyenne (multiplication) à particulièrement lente (division). Il faut cependant signaler que lorsqu'on effectue un décalage à droite, certains bits de notre nombre vont sortir du résultat et être perdus : le résultat est tronqué ou arrondi vers zéro. Plus précisément, le résultat d'un décalage à droite de n rangs sera égal à la partie entière du résultat de la division par formula_31.
Le tableau ci-dessous indique les notations utilisées pour les décalages.
Les décalages arithmétiques.
Le décalage logique ne donne cependant pas de bons résultats avec des nombres signés négatifs : on obtient un résultat qui n'a pas grand sens mathématiquement. Il faut dire que le bit de signe est alors remplacé par un zéro, ce qui peut inverser le signe du résultat. Une solution intuitive est de conserver le bit de signe, de ne pas le décaler. Mais en faisant cela, que mettre dans le bit situé juste avant le bit de poids fort après décalage ? On pourrait penser mettre un zéro dedans, mais cela ne donnerait pas le bon résultat avec les nombres négatifs. La solution est en fait de recopier le bit de signe dans ce bit. Tout se passe comme si on faisait le décalage normalement, comme un décalage logique, mais que le bit de poids fort était cependant conservé au lieu d'être remplacé par un zéro. Ce faisant, le bit de signe est conservé et le décalage est malgré tout effectué correctement.
En faisant cela, on obtient un décalage qui effectue correctement des multiplications/divisions par formula_31 sur des nombres signés. De tels décalages sont appelés décalages arithmétiques ("arithmetical shift" en anglais). La différence avec un décalage logique est la méthode d'arrondi des nombres négatifs. Avec les décalages arithmétiques, les nombres négatifs sont arrondis vers moins l'infini. Pour donner un exemple, 92 sera arrondi en 4, tandis que −92 sera arrondi en −5.
Les rotations de bits.
Les rotations sont identiques aux décalages, à part que les bits qui sortent du nombre sont ceux qui rentrent pour combler les vides.
Ces opérations sont très utiles en cryptographie, et sont notamment très utilisées dans certains algorithmes de chiffrement. Les rotations sont aussi très utiles dans certains cas particuliers dans lesquels on doit manipuler des données bits par bits. Par exemple, un calcul du nombre de bits à 1 dans un nombre peut s'implémenter de façon naïve avec des instructions de rotation.
Le tableau ci-dessous indique les notations utilisées pour les rotations.
Quelques règles de calcul utiles.
Dans la suite du cours, nous ferons souvent usage de quelques équations qui mélangerons les différentes opérations bit à bit. Ne vous étonnez donc pas si vous voyez des équations de ce style :
Il existe quelques règles mathématiques qui nous permettront de simplifier de telles équations.
Les règles pour les expressions booléennes.
Commençons par les règles qui impliquent uniquement des opérations bit à bit/booléens. Nous en avons déjà vu la plus grande partie plus haut, en parlant de la distributivité et de l'associativité des différents opérateurs. En voici la liste complète :
Les règles pour les expressions booléennes et arithmétiques.
Il est parfaitement possible de mixer des opérations booléennes avec des opérations arithmétiques. Par exemple, on peut se demander ce que vaut formula_38, un calcul qui sera notamment beaucoup utilisé dans la suite du cours. Les règles qui régissent les mélanges/interactions entre opérations mathématiques et opérateurs bit à bit dépendent du codage des nombres, notamment pour les nombres signés. Nous allons supposer que les nombres signés sont codés en complètement à deux. Les règles qui en découlent sont résumées dans le tableau suivant :
Les équations pour l'opposé et la soustraction peuvent se déduire assez facilement de l'équation formula_39, définition de l'opposée d'un nombre en complètement à deux. En guise d'exercice, vous pouvez tenter d'en déduire l'équation formula_40. Si vous utilisez les règles sur les opérateurs booléens, vous devriez y arriver sans trop de peine.
Les règles pour les expressions booléennes et comparaisons.
Il est parfaitement possible de comparer des expressions booléennes, et certaines égalités ou inégalités sont toujours vraies. On peut rapidement se rendre compte que :
Pour les opérations mathématiques, les relations suivantes sont importantes à connaître :