Référence de JavaScript 1.5 Core:Opérateurs:Opérateurs binaires
Un article de MDC.
Sommaire |
[modifier] Résumé
Les opérateurs binaires traitent leurs opérandes comme des séquences de 32 bits (zéros et uns), plutôt que comme des nombres décimaux, hexadécimaux ou octaux. Par exemple, le nombre décimal neuf a une représentation binaire de 1001. Les opérateurs binaires traitent de telles représentations binaires, mais renvoient des valeurs numériques JavaScript standards.
| Opérateurs | |
| Implémentation : | JavaScript 1.0 |
| Version ECMA : | ECMA-262 |
Le tableau qui suit résume les opérateurs binaires de JavaScript :
| Opérateur | Utilisation | Description |
|---|---|---|
| ET binaire | a & b |
Renvoie un 1 pour chaque position de bit pour laquelle les bits correspondants des deux opérandes sont des 1. |
| OU binaire | a | b |
Renvoie un 1 pour chaque position de bit pour laquelle le bit correspondant d'au moins un des deux opérandes est un 1 . |
| OU exclusif binaire (XOR) | a ^ b |
Renvoie un 1 pour chaque position de bit pour laquelle le bit correspondant d'un seul des deux opérandes est un 1. |
| NON binaire | ~ a |
Inverse les bits de son opérande. |
| Décalage à gauche | a << b |
Décale a en représentation binaire de b bits vers la gauche, en introduisant des zéros par la droite. |
| Décalage à droite avec propagation du signe | a >> b |
Décale a en représentation binaire de b bits vers la droite, en rejetant les bits à droite. |
| Décalage à droite avec introduction de zéros | a >>> b |
Décale a en représentation binaire de b bits vers la droite, en rejetant les bits à droite et en introduisant des zéros par la gauche. |
[modifier] Entiers 32-bits signés
Les opérandes de tous les opérateurs binaires sont convertis en entiers 32-bits signés en ordre big-endian et en format de complément à deux. L'ordre big-endian signifie que le bit le plus significatif (la position du bit qui a la plus grande valeur) est le bit le plus à gauche si les 32 bits sont disposés sur une ligne horizontale. Le format de complément à deux signifie que la contrepartie négative d'un nombre (par exemple 5 pour -5) est l'inversion de tous les bits du nombre (NON binaire du nombre, c'est-à-dire son complément à un) plus un. Par exemple, la représentation suivante encode l'entier 314 (base 10) :
00000000000000000000000100111010
La représentation suivante encode ~314, c'est-à-dire le complément à un de 314 :
11111111111111111111111011000101
Finalement, la représentation suivante encode -314, c'est-à-dire le complément à deux de 314 :
11111111111111111111111011000110
Le complément à deux garantit que le bit le plus à gauche soit 0 lorsque le nombre est positif, et 1 lorsque le nombre est négatif. C'est pourquoi on l'appelle le bit de signe.
Le nombre 0 est l'entier constitué intégralement de bits à 0 .
Le nombre -1 est l'entier constitué intégralement de bits à 1 .
[modifier] Opérateurs logiques binaires
Conceptuellement, les opérateurs logiques binaires fonctionnent de la manière suivante :
- Les opérandes sont convertis en entiers 32 bits et sont exprimés sous la forme d'une série de bits (zéros et uns).
- Chaque bit du premier opérande est combiné avec le bit correspondant du second opérande : le premier bit avec le premier bit, le second bit avec le second bit, et ainsi de suite.
- L'opérateur est appliqué à chaque paire de bits, et le résultat est construit bit après bit.
[modifier] & (ET binaire)
Effectue l'opération ET (AND) sur chaque paire de bits. a ET b donne 1 uniquement si à la fois a et b sont 1 . La table de vérité pour l'opération AND est :
| a | b | a ET b |
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
Exemple :
9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 & 9 (base 10) = 00000000000000000000000000001000 (base 2) = 8 (base 10)
Utiliser le ET binaire avec n'importe quel nombre x et zéro donne zéro.
Utiliser le ET binaire avec n'importe quel nombre x et -1 donne x.
[modifier] | (OU binaire)
Effectue l'opération OU (OR) sur chaque paire de bits. a OU b donne 1 si a ou b vaut 1. La table de vérité pour l'opération OU est :
| a | b | a OU b |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 | 9 (base 10) = 00000000000000000000000000001111 (base 2) = 15 (base 10)
Utiliser le OU binaire avec n'importe quel nombre x et 0 donne x.
Utiliser le OU binaire avec n'importe quel nombre x et -1 donne -1.
[modifier] ^ (XOR binaire)
Effectue l'opération XOR (OU exclusif) sur chaque paire de bits. a XOR b donne 1 si a et b sont différents. La table de vérité pour l'opération XOR est :
| a | b | a XOR b |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
Exemple :
9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 ^ 9 (base 10) = 00000000000000000000000000000111 (base 2) = 7 (base 10)
Utiliser le XOR binaire avec n'importe quel nombre x et 0 donne x.
Utiliser le XOR binaire avec n'importe quel nombre x et -1 donne ~x.
[modifier] ~ (NON binaire)
Effectue l'opération NON (NOT) sur chaque bit. NON a donne la valeur inversée (c'est-à-dire le complément à un) de a. La table de vérité de l'opération NON est :
| a | NON a |
| 0 | 1 |
| 1 | 0 |
Exemple :
9 (base 10) = 00000000000000000000000000001001 (base 2)
--------------------------------
~9 (base 10) = 11111111111111111111111111110110 (base 2) = -10 (base 10)
Utiliser le NON binaire avec n'importe quel nombre x donne -(x + 1). Par exemple, ~5 donne -6.
[modifier] Opérateurs de décalage binaire
Les opérateurs de décalage binaire (shift) prennent deux opérandes : le premier est une valeur à décaler et le second spécifie le nombre de positions de bits duquel le premier opérande doit glisser. La direction de l'opération de décalage est contrôlée par l'opérateur utilisé.
Les opérateurs de décalage convertissent leurs opérandes en entiers 32 bits en ordre big-endian et renvoient un résultat du même type que l'opérande de gauche.
[modifier] << (décalage à gauche)
Cet opérateur décale le premier opérande du nombre de bits spécifié vers la gauche. Les bits surnuméraires éjectés à gauche sont perdus. Des bits à zéro sont insérés par la droite.
Par exemple, 9 << 2 donne 36 :
9 (base 10) : 00000000000000000000000000001001 (base 2)
--------------------------------
9 << 2 (base 10) : 00000000000000000000000000100100 (base 2) = 36 (base 10)
[modifier] >> (décalage à droite avec propagation du signe)
Cet opérateur décale le premier opérande du nombre de bits spécifié vers la droite. Les bits surnuméraires éjectés à droite sont perdus. Des copies du bit le plus à gauche sont insérés par la gauche. Comme le bit le plus a gauche a la même valeur qu'avant l'opération, le bit de signe (celui qui est le plus à gauche) ne change pas. D'où ce qu'on appelle la « propagation du signe ».
Par exemple, 9 >> 2 donne 2 :
9 (base 10) : 00000000000000000000000000001001 (base 2)
--------------------------------
9 >> 2 (base 10) : 00000000000000000000000000000010 (base 2) = 2 (base 10)
De même, -9 >> 2 donne -3, parce que le signe est préservé :
-9 (base 10) : 11111111111111111111111111110111 (base 2)
--------------------------------
-9 >> 2 (base 10) : 11111111111111111111111111111101 (base 2) = -3 (base 10)
[modifier] >>> (décalage à droite avec insertion de zéros)
Cet opérateur décale le premier opérande du nombre de bits spécifié vers la droite. Les bits surnuméraires éjectés à droite sont perdus. Des bits à zéro sont insérés par la gauche. Le bit de signe devient 0, donc le résultat est toujours positif.
Pour les nombres non négatifs, le décalage à droite avec insertion de zéros et le décalage à droite avec propagation du signe donnent le même résultat. Par exemple, 9 >>> 2 donne 2, tout comme 9 >> 2 :
9 (base 10) : 00000000000000000000000000001001 (base 2)
--------------------------------
9 >>> 2 (base 10) : 00000000000000000000000000000010 (base 2) = 2 (base 10)
Cependant, ce n'est pas le cas des nombres négatifs. Par exemple, -9 >>> 2 donne 1073741821, ce qui est différent de -9 >> 2 (qui donne -3) :
-9 (base 10) : 11111111111111111111111111110111 (base 2)
--------------------------------
-9 >>> 2 (base 10) : 00111111111111111111111111111101 (base 2) = 1073741821 (base 10)
[modifier] Exemples
[modifier] Exemple : flags et bitmasks
Les opérateurs logiques binaires sont souvent utilisés pour créer, manipuler et lire des séquences de flags, qui sont comme des variables binaires. On pourrait très bien utiliser des variables à la place de ces séquences binaires, mais des flags binaires prennent nettement moins de mémoire (par un facteur de 32).
Supposons que l'on ait 3 flags :
- flag A : nous avons un problème de fourmis
- flag B : nous avons une chauve-souris
- flag C : nous avons un chat
- flag D : nous avons un canard
Ces flags sont représentés par une séquence de bits : DCBA. Lorsqu'un flag est positionné, il a une valeur de 1. Sinon, il a une valeur de 0. Supposons qu'une variable flags a la valeur binaire de 0101 :
var flags = 0x5; // 0101 en binaire
Cette valeur indique :
- le flag A est vrai (nous avons un problème de fourmis) ;
- le flag B est faux (nous n'avons pas de chauve-souris) ;
- le flag C est vrai (nous avons un chat) ;
- le flag D est faux (nous n'avons pas de canard).
Comme les opérateurs binaires sont sur 32 bits, 0101 est en fait 00000000000000000000000000000101, mais les zéros qui précèdent peuvent être négligés étant donné qu'ils ne contiennent aucune information significative.
Un bitmask est une séquence de bits qui peuvent manipuler et/ou lire des flags. Typiquement, un masque « primitif » pour chaque flag est défini :
var FLAG_A = 0x1; // 0001 var FLAG_B = 0x2; // 0010 var FLAG_C = 0x4; // 0100 var FLAG_D = 0x8; // 1000
De nouveaux masques peuvent être créés à l'aide des opérateurs logiques binaires sur ces masques primitifs. Par exemple, le masque 1011 peut être créé avec une opération OU sur FLAG_A, FLAG_B et FLAG_D :
var mask = FLAG_A | FLAG_B | FLAG_D; // 0001 | 0010 | 1000 => 1011
Des valeurs de flag particulières peuvent être extraites à l'aide d'une opération ET avec un bitmask, où chaque bit avec la valeur 1 va « extraire » le flag qui correspond. Le bitmask masque les flags dont on n'a pas besoin en effectuant l'opération ET avec des zéros (d'où le terme « bitmask »). Par exemple, le masque 0100 peut être utilisé pour voir si le flag C est positionné :
// si l'on a un chat
if (flags & FLAG_C) { // 0101 & 0100 => 0100 => true
// faire quelque chose
}
Un masque avec plusieurs flags positionnés agit comme un « et/ou ». Par exemple, les deux instructions suivantes sont équivalentes :
// si l'on a une chauve-souris ou que l'on a un chat
if ((flags & FLAG_B) || (flags & FLAG_C)) { // (0101 & 0010) || (0101 & 0100) => 0000 || 0100 => true
// faire quelque chose
}
// si l'on a une chauve-souris ou un chat
var mask = FLAG_B | FLAG_C; // 0010 | 0100 => 0110
if (flags & mask) { // 0101 & 0110 => 0100 => true
// faire quelque chose
}
Les flags peuvent être positionnés en utilisant l'opération OU avec un masque, où chaque bit de la valeur 1 définira le flag correspondant, si celui-ci n'est pas déjà positionné. Par exemple, le masque 1010 peut être utilisé pour positionner les flags C et D :
// oui, on a un chat et un canard var mask = FLAG_C | FLAG_D; // 0100 | 1000 => 1100 flags |= mask; // 0101 | 1100 => 1101
Les flags peuvent être remis à zéro en utilisant l'opération ET avec un masque, où chaque bit avec la valeur 0 remettra à zéro le flag correspondant s'il ne l'est pas déjà. Ce masque peut être créé avec l'opération NOT sur les masques primitifs. Par exemple, le masque 1010 peut être utilisé pour remettre à zéro les flags A et C :
// non, nous n'avons ni problème de fourmis ni un chat var mask = ~(FLAG_A | FLAG_C); // ~0101 => 1010 flags &= mask; // 1101 & 1010 => 1000
Le masque aurait également pu être créé avec ~FLAG_A & ~FLAG_C (Loi de De Morgan) :
// non, nous n'avons pas de problème de fourmis, et n'avons pas de chat var mask = ~FLAG_A & ~FLAG_C; flags &= mask; // 1101 & 1010 => 1000
Les flags peuvent être inversés en utilisant l'opération XOR avec un masque, où chaque bit avec la valeur 1 inversera le flag correspondant. Par exemple, le masque 0110 peut être utilisé pour inverser les flags B et C :
// si on n'avait pas de chauve-souris, on en a maintenant une. // si on en avait une, on ne l'a plus. Même chose pour les chats. var mask = FLAG_B | FLAG_C; flags = flags ^ mask; // 1100 ^ 0110 => 1010
Finalement, les flags peuvent être tous inversés avec l'opérateur NON :
// entrée dans un univers parallèle... flags = ~flags; // ~1010 => 0101