Opérations sur les bits

Opérations bit à bit, ou bitwise operations en anglais.
Les opérations bit à bit sont des calculs sur les bits qui utilisent l’algèbre de Boole: NOT, AND, OR, XOR et décalages.


Opérations sur les bits en programmation

Les opérations sur les bits sont très utiles en programmation pour gérer des listes d’options (multiples de 2):

<?php

define('UAG_OPTION1', 1);     # 001
define('UAG_OPTION2', 2);     # 010
define('UAG_OPTION3', 4);     # 100

function hasOption($config, $opt) {
    return ($config & $opt) > 0;
}
function removeOption($config, $opt) {
    return ($config & ~$opt);
}
function addOption($config, $opt) {
    return ($config | $opt);
}

$opts = UAG_OPTION1;                             # 001
$opts = addOption($opts, UAG_OPTION2);           # 011
$opts = addOption($opts, UAG_OPTION3);           # 111
$opts = removeOption($opts, UAG_OPTION2);        # 101

NB Il n’est pas nécessaire d’apprendre par coeur tous les multiples de 2 !
Connaître 1,2,4,8 puis utiliser la notation hexadécimale :

ValeurReprésentation binaire
11
210
4100
81000
0x1010000
0x20100000
0x401000000
0x8010000000
0x100100000000

NOT

Négation: les bits qui sont positionnés à 1 dans a sont positionnés à 0, et vice-versa

NOT 0111
  = 1000

En programmation:
~ permet d’inverser.

~~ est parfois utilisé comme substitut de Math.floor

~~'-1' = -1
~~true = 1
~~false = 0
~~5.6 = 5

AND

Et logique: les bits positionnés à 1 dans a ET b sont positionnés à 1

    0101
AND 0011
  = 0001

En programmation:
& (and) permet de tester la valeur d’un bit ou, avec la négation, de supprimer des bits.

<?php
error_reporting(E_ALL & ~E_NOTICE);  ## Afficher toutes les erreurs SAUF les notices

if(error_reporting() & E_NOTICE) {
    echo "Reporting of Notices is on";
} else {
    echo "Reporting of Notices is off";
}

& 1 est parfois utilisé pour vérifier la parité d’un nombre

<?php
if($n & 1) {
    echo "ODD!";
} else {
    echo "EVEN!";
}

OR

Ou logique: les bits positionnés à 1 dans a OU b sont positionnés à 1

   0101
OR 0011
 = 0111

En programmation:
| (or) permet d’ajouter

<?php
error_reporting(E_ERROR | E_RECOVERABLE_ERROR);  # Afficher les erreurs ET les erreurs recouvrables

XOR

Ou exclusif: Les bits positionnés à 1 dans a OU b MAIS PAS LES DEUX sont positionnés à 1

    0101
XOR 0011
  = 0110

En programmation:
^ (xor) permet de retirer un bit s’il est vrai, de l’ajouter s’il est faux (= toggle).

<?php
$hasOption3 = $opts & UAG_OPTION3;
if($hasOption3) {
   $opts = ($opts ^ UAG_OPTION3);  # Enleve UAG_OPTIONS3
} else {
   $opts = ($opts ^ UAG_OPTION3);  # Ajoute UAG_OPTIONS3
}

^ est parfois utilisé pour permuter deux variables sans utiliser d’emplacement mémoire supplémentaire

<?php
$a = 11;
$b = 22;

$a = $a ^ $b;
$b = $a ^ $b;
$a = $a ^ $b;
echo $a . " " . $b; // 22 11

Décalage à gauche

Le décalage à gauche décale tous les bits vers la gauche, ce qui revient à une multiplication par 2 pour un décalage de 1 (2^1), 4 pour un décalage de 2 (2^2), 8 pour un décalage de 3 (2^3), etc.

   00010111 (+23) LEFT-SHIFT
=  00101110 (+46)

En programmation:
<< (left shift) permet de multiplier par des puissances de 2 très rapidemment

<?php
function listOptions($opts) {
    $nb = 3;             # Nombre d'options possibles
    $n  = pow(2, $nb-1); # Valeur de la dernière option ($nb-1 puissance 2)

    // Parcours multiples de 2 (multiplication)
    $j  = 1;
    for($i = 1; $i <= $n; $i <<= 1) {
        echo ($opts & $i ? '1' : '.');
    }
    echo '<br>';
}
listOptions(UAG_OPTION1);                             # 1..
listOptions(UAG_OPTION1 | UAG_OPTION2);               # 11.
listOptions(UAG_OPTION1 | UAG_OPTION2 | UAG_OPTION3); # 111

Décalage à droite

Le décalage à droite décale tous les bits vers la droite, ce qui revient à une division par 2 pour un décalage de 1 (2^1).

   00010111 (+23) RIGHT-SHIFT
=  00001011 (+11)

En programmation:
>> (right shift) permet de diviser par 2 très rapidemment

<?php
function listOptions($opts) {
    $nb = 3;

    // Parcours incrémental + division sur variable cible
    for($i = 1; $i <= $nb; $i++) {
        echo $i . ':' . ($opts & 1 ? 'x' : '.') . ' ';
        $opts >>=1 ;
    }
    echo '<br>';
}
listOptions(UAG_OPTION1);                             # 1..
listOptions(UAG_OPTION1 | UAG_OPTION2);               # 11.
listOptions(UAG_OPTION1 | UAG_OPTION2 | UAG_OPTION3); # 111