Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Utilisation des opérateurs binaires

Les opérateurs ++ et -- Manipulation des types flottants



Accès rapide :
La vidéo
Introduction au système binaire
Généralité
Les opérateurs binaires
L'opérateur binaire AND
L'opérateur binaire OR (le ou inclusif)
L'opérateur binaire XOR (le ou exclusif)
L'opérateur binaire NOT
Représentation des nombres négatifs
Les opérateurs Java relatifs aux opérations de base
Les opérateurs de décalage de bits
Les opérateurs d'affectation

La vidéo

Cette vidéo vous montre comment utiliser les différents opérateurs de manipulation de la représentation binaire de vos entiers. Elle montre aussi comment afficher un entier dans sa représentation binaire.


Utilisation des opérateurs binaires

Introduction au système binaire

Généralité

Nous l'avons vu dans un chapitre précédent, Java permet d'exprimer la valeur de vos entiers via différentes bases numériques (le binaire, l'octal, le décimal et l'hexadécimal). Dans allons, dans ce chapitre, porter notre attention sur la base numérique binaire : on parle aussi de système binaire.

En base binaire, on utilise uniquement deux chiffres : le 0 et le 1. Le tableau suivant vous présente quelques valeurs exprimées en binaire, mais aussi en décimal et en hexadécimal.

Valeur en binaire Valeur en décimal Valeur en hexadécimal
00000000 0 0
00000001 1 1
00000010 2 2
00000011 3 3
00000100 4 4
00000101 5 5
00000110 6 6
00000111 7 7
00001000 8 8
00001001 9 9
00001010 10 A
00001011 11 B
00001100 12 C
00001101 13 D
00001110 14 E
00001111 15 F
00010000 16 10
00100000 32 20
01000000 64 40
10000000 128 80
11111111 255 FF

Dans le système de numération binaire, un chiffre est appelé un bit. En électronique cette notion de bit est très importante car elle correspond à l'état électrique d'un fil électrique (en caricaturant) : 0 correspond à l'absence de courant sur ce fil et 1 correspond à la présence du courant sur ce fil. Il faut aussi noter que sur l'électronique actuellement utilisée dans nos ordinateurs, on utilise des transistors qui ne savent gérer que deux états : 0 ou 1.

Ce dernier point est en passe de changer avec l'avènement des ordinateurs quantiques, mais c'est une autre histoire.

Il est aussi à noter, qu'on a pris l'habitude, en électronique et donc en informatique, de regrouper les bits par blocs de 8. On appelle un tel ensemble un octet. Comme un octet est constitué de 8 bits et comme chacun de ces bits ne peut valoir que 0 ou 1 (2 états), cet octet peut donc avoir 256 états distincts (de 0 à 255).

En analysant ce tableau on peut constater que chaque position de bit, si le bit est fixé à 1, correspond à une puissance de 2. Un décalage de tous les bits d'un cran vers la gauche, en ajoutant un 0 en première position, correspond donc à une multiplication par 2. De même, un décalage de tous les bits d'un cran vers la droite, en ajoutant un 0 en dernière position, correspond donc à une division entière par 2.
On constate aussi que l'hexadécimal permet de représenter n'importe quelle valeur d'un octet sur deux digits hexadécimaux (de 00 à FF), ce qui est relativement pratique en informatique. Le chiffre hexadécimal de gauche correspond aux quatre bits de gauche (en représentation binaire) et le chiffre de droite correspond aux quatre bits de droite (en représentation binaire). 24 = 16 et 16*16 = 256.

Les opérateurs binaires

Outre les opérations arithmétiques classiques (addition, soustraction, multiplication, division), le système binaire propose des opérateurs de manipulation de bits. Ces opérateurs sont appelés AND (le « et » binaire), OR (le « ou » binaire, aussi appelé « ou inclusif »), le XOR (le « ou exclusif » binaire) et le NOT (le « non » binaire, autrement dit la négation binaire). Ces operateurs travaillent sur une paire de bits, à l'exception du NOT qui travaille sur un unique bit.

L'opérateur binaire AND

Le tableau suivant précise le fonctionnement de l'opérateur AND.

AND 0 1
0 0 0
1 0 1

On peut appliquer cet opérateur sur deux valeurs complexes : pour chaque pair de bits, on calculera 1 si les deux bits de même position dans les deux valeurs considérées sont bien fixés à 1. Sinon, on calculera 0. Par exemple :

\ Binaire Décimal Hexadécimal
Première valeur 01010101 85 55
Seconde valeur 11110000 240 F0
AND 01010000 80 50

L'opérateur binaire OR (le ou inclusif)

Le tableau suivant précise le fonctionnement de l'opérateur OR.

OR 0 1
0 0 1
1 1 1

On peut appliquer cet opérateur sur deux valeurs complexes : pour chaque pair de bits, on calculera 1 si ou moins un des deux bits de même position dans les deux valeurs considérées est fixé à 1. Sinon, on calculera 0. Par exemple :

\ Binaire Décimal Hexadécimal
Première valeur 01010101 85 55
Seconde valeur 11110000 240 F0
OR 11110101 245 F5

L'opérateur binaire XOR (le ou exclusif)

Le tableau suivant précise le fonctionnement de l'opérateur XOR.

XOR 0 1
0 0 1
1 1 0

On peut appliquer cet opérateur sur deux valeurs complexes : pour chaque pair de bits, on calculera 1 si un seul des deux bits de même position dans les deux valeurs considérées est fixé à 1. Sinon, on calculera 0. Par exemple :

\ Binaire Décimal Hexadécimal
Première valeur 01010101 85 55
Seconde valeur 11110000 240 F0
XOR 10100101 165 A5

L'opérateur binaire NOT

Le tableau suivant précise le fonctionnement de l'opérateur NOT.

Bit NOT
0 1
1 0

On peut appliquer cet opérateur sur une valeur complexe : chacun de ses bits sera inversé. Par exemple :

\ Binaire
Une valeur 01010101
NOT de cette valeur 10101010

Représentation des nombres négatifs

En informatique les nombres signés sont gérés d'une manière particulière. Pour un type entier quelconque, le bit dit de point fort (celui le plus à gauche) est appelé bit de signe. S'il est fixé à 1, on a alors à faire à une valeur négative. S'il est à 0, la valeur est donc considéré comme positive. Dans l'exemple qui suit, on considère le type byte du langage Java. Il occupe donc 1 octet, soit 8 bits. En fonction de l'état du 8ième bit, nous aurons donc à faire à une valeur positive ou négative.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
public class Demo {

    public static void main( String [] args ) {
    
        byte value = (byte) 0b00001111;
        System.out.println( value );    // Affiche 15
        value = (byte) 0b01000000;
        System.out.println( value );    // Affiche 64
        value = (byte) 0b10000000;
        System.out.println( value );    // Affiche -128
        value = (byte) 0b11111111;
        System.out.println( value );    // Affiche -1
        
        int value2 = 0b10000000;
        System.out.println( value2 );   // Affiche 128, car le bit de signe d'un int est en position 32.
        
    }
}
Vérification de sémantique du bit de signe
les transtypages en byte sont nécessaire car par défaut une valeur entière Java est typée int. Il faut donc ramener les valeurs du type int vers byte.

Cette représentation des nombres négatifs utilisée par Java est appelée « Complément à deux ». Cette représentation cherche à éviter d'avoir deux formes de la valeur 0 (signé ou non), contrairement à la représentation de type « complément à un ».

Les opérateurs Java relatifs aux opérations de base

Il est maintenant temps de voir comment représenter les opérateurs vu précédemment (AND, OR, XOR et NOT) en Java. Le tableau suivant précise les caractères utilisés pour représenter chacun des opérateurs binaires considérés. Il est vrai qu'il est dommage que Java est récupéré ces caractères du langage C plutôt que d'utiliser des mots clés : c'est moins lisible, mais bon, c'est comme çà.

Opérateurs binaires AND OR XOR NOT
Opérateurs binaires Java & | ^ ~

Avant de procéder à nos premiers tests sur ces opérateurs, je voudrais répondre à cette question : comment vérifier les résultats qui vont être produits ? Le mieux serait d'afficher les résultats sous forme binaire. Pour ce faire nous utiliserons la méthode Integer.toBinaryString. Voici un petit exemple d'utilisation, en notant bien que je cherche ici à remplir par la gauche avec des caractères 0 si la taille de la chaîne de caractères produite est inférieure à 4.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
public class Demo {

    public static void main( String [] args ) {
    
        for( int i=0; i<16; i++ ) {
            String str = Integer.toBinaryString( i );
            while( str.length() < 4 ) str = "0" + str;
            System.out.println( str );
        }     
           
    }
}
Affichage sous forme binaire

Voici les résultats produits par ce programme.

0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111

Maintenant, testons ces fameux opérateurs binaires. Le programme suivant effectue quelques calculs grâce à eux.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
public class Demo {

    public static void main( String [] args ) {
    
        int value1 = 0b10101010;
        int value2 = 0b00001111;
        
        // & (AND)   | (OR)    ^ (XOR)    ~ (NOT)
        System.out.println( "NOT - " + Integer.toBinaryString( ~value1 ) );
        System.out.println( "AND - " + Integer.toBinaryString( value1 & value2 ) );
        System.out.println( "OR  - " + Integer.toBinaryString( value1 | value2 ) );
        System.out.println( "XOR - " + Integer.toBinaryString( value1 ^ value2 ) );
           
    }
    
}
Utilisation des opérateurs binaires Java

Voici les résultats produits par ce programme.

NOT - 11111111111111111111111101010101
AND - 1010
OR  - 10101111
XOR - 10100101

Les opérateurs de décalage de bits

Java vous propose deux autres opérateurs permettant des décaler les bits d'un certain nombre de rangs. L'opérateur << permet de décaler les bits vers la gauche, alors que l'opérateur >> permet un décalage vers la droite. Dans les deux cas, l'opérande de droite de l'opérateur (un opérande est en quelque sorte un paramètre de l'opérateur, mais utilisons les termes consacrés) correspond au nombre de rangs sur lesquels opérer le décalage. Voici un petit exemple montrant ces possibilités.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
public class Demo {

    public static void main( String [] args ) {
    
        int value = 0b00010001;
        
        // << (left shift)    >> (right shift)
        System.out.println( "2 x <<  - " + Integer.toBinaryString( value ) 
              + " -> " + Integer.toBinaryString( value << 2 )
                          + " [" + value + " -> " + (value << 2) + "]");
        System.out.println( "2 x >>  - " + Integer.toBinaryString( value )
                          + " -> " + Integer.toBinaryString( value >> 2 ) 
                          + " [" + value + " -> " + (value >> 2) + "]");
           
    }
    
}
Utilisation des opérateurs de décalage de bits

Voici les résultats produits par ce programme.

2 x <<  - 10001 -> 1000100 [17 -> 68]
2 x >>  - 10001 -> 100 [17 -> 4]
n'oubliez pas qu'un décalage vers la gauche correspond à une multiplication par 2 et qu'un décalage vers la droite correspond à une division par 2. En conséquence, l'exemple ci-dessous multiplie 17 par 4 et divise 17 par 4 (division entière).

Il faut aussi noter l'existance de l'opérateur >>>. C'est un opérateur de décalage de bits à utiliser pour des valeurs que vous considérées comme étant non signées. Du coup, des bits à zéro seront systématiquement insérés à droite. N'oubliez pas qu'en représentation signé, le bit de point le plus fort correspond au signe de votre valeur numérique (0 == positif et 1 == négatif).

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
package fr.koor.annotations;

public class Start {

    public static void main( String[] args ) {

        int a = -8;

        // Manipulation en conservant le bit de signe
        System.out.printf( "-8 >> 1 == %d\n", (a >> 1) );
        System.out.printf( "-8 >> 2 == %d\n", (a >> 2) );

        // Manipulation en considérant la valeur comme étant non signée.
        System.out.printf( "-8 >>> 1 == %d\n", (a >>> 1) );
        System.out.printf( "-8 >>> 2 == %d\n", (a >>> 2) );

    }
    
}
Décalage de bits avec des entiers signés et non signés

Et voici les résultats produits par cet exemple :

-8 >> 1 == -4
-8 >> 2 == -2
-8 >>> 1 == 2147483644
-8 >>> 2 == 1073741822

Les opérateurs d'affectation

Pour clore ce chapitre, notez que les opérateurs que nous venons d'étudier peuvent être cumulés à une affectation. Ainsi l'expression a &= 0b1111 est équivalente à l'expression a = a & 0b1111. Il en va de même pour les autres opérateurs proposés. Voici la liste de toutes les combinaisons possibles avec un opérateur d'affectation.

Opérateur combiné Exemple d'utilisation Equivalence
&= a &= 0b1111; a = a & 0b1111;
|= a |= 0b1111; a = a | 0b1111;
^= a ^= 0b1111; a = a ^ 0b1111;
<<= a <<= 0b1111; a = a << 0b1111;
>>= a >>= 0b1111; a = a >> 0b1111;
>>>= a >>>= 0b1111; a = a >>> 0b1111;

Voici un petit exemple d'utilisation de ces opérateurs.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
public class Demo {

    public static void main( String [] args ) {
    
        int value = 0b00010001;
        value <<= 2;               //   value = value << 2;
        System.out.println( "<<=  - " + Integer.toBinaryString( value ) );

        value = 0b00010001;
        value >>= 2;               //   value = value >> 2;
        System.out.println( ">>=  - " + Integer.toBinaryString( value ) );
           
    }
    
}
Utilisation des opérateurs combinés


Les opérateurs ++ et -- Manipulation des types flottants