Les opérateurs binaires traitent leurs opérandes comme des séquences de 32 bits (des zéros et des 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.
Le tableau qui suit résume les opérateurs binaires de JavaScript :
Opérateur | Utilisation | Description |
---|---|---|
ET binaire | a & b |
Renvoie un |
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. |
Entiers sur 32 bits signés
Les opérandes de tous les opérateurs binaires sont convertis en entiers signés sur 32 bits 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
.
0 (base 10) = 00000000000000000000000000000000 (base 2)
Le nombre -1 est l'entier constitué intégralement de bits à 1
.
-1 (base 10) = 11111111111111111111111111111111 (base 2)
Le nombre -2147483648
(qui correspond à -0x80000000
en notation hexadécimale) est l'entier uniquement composé de 0, à l'exception du premier bit (le plus à gauche) qui vaut 1.
-2147483648 (base 10) = 10000000000000000000000000000000 (base 2)
Le nombre 2147483647
(qui correspond à 0x7fffffff
en notation hexadécimale) est l'entier uniquement composé de 1, à l'exception du premier bit (le plus à gauche) qui vaut 0.
2147483647 (base 10) = 01111111111111111111111111111111 (base 2)
Les nombres -2147483648
et 2147483647
sont respectivement le nombre le plus petit et le plus grand qu'on peut représenter sur 32 bits (signés).
Opérateurs logiques binaires
Conceptuellement, les opérateurs logiques binaires fonctionnent de la manière suivante :
- Les opérandes sont convertis en entiers sur 32 bits et exprimés sous la forme d'une série de bits (des 1 et des 0). Les nombres sur plus de 32 bits voient leurs bits supplémentaires supprimés :
Avant : 11100110111110100000000000000110000000000001 Après : 10100000000000000110000000000001
- 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.
& (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 ET est :
a | b | a ET b |
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
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.
| (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.
^ (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 |
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.
~ (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 |
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.
Voici un autre exemple avec indexOf
:
var str = 'ouaf'; var carRecherché = 'a'; // une autre méthode pour tester si (-1*str.indexOf('a') <= -1) if (~str.indexOf(carRecherché)) { // carRecherché est dans la chaîne } else { // carRecherché n'est pas dans la chaîne } // voici les valeurs renvoyées par (~str.indexOf(carRecherché)) // o == -1 // u == -2 // a == -3 // f == -4
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. L'opérande droit doit être inférieur à 32, sinon les cinq bits les plus faibles seront utilisés.
<< (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)
Décaler un nombre x de y bits vers la gauche renverra .
>> (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)
>>> (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)
Exemples
Exemple : flags et bitmasks
Les opérateurs logiques binaires sont souvent utilisés pour créer, manipuler et lire des séquences deflags , 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 4 flags :
- flag A : nous avons une araignée
- flag B : nous avons une belette
- flag C : nous avons un chat
- flag D : nous avons un dinosaure
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 une araignée) ;
- le flag B est faux (nous n'avons pas de belette) ;
- le flag C est vrai (nous avons un chat) ;
- le flag D est faux (nous n'avons pas de dinosaure).
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 0101 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 on a une belette ou si on a un chat if ((flags & FLAG_B) || (flags & FLAG_C)) { // (0101 & 0010) || (0101 & 0100) => 0000 || 0100 => true // faire quelque chose }
// si on a une belette ou si on a 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 dinosaure 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 pas d'araignée ou de 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 d'araignée ou 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 belette, 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
Codes de conversion
Pour convertir une String
binaire en un Number
(en base 10):
var chaîneBinaire = "1011"; var monNombre = parseInt(chaîneBinaire, 2); console.log(monNombre); // affiche 11 (1011 en base 2)
Pour convertir un Number
(en base 10) en une String
binaire :
var monNombre = 11; var chaîneBinaire = monNombre.toString(2); console.log(chaîneBinaire); // affiche 1011 (11 en base 10)
Automatiser la création d'un masque
Si vous devez créer plusieurs masques à partir de booléens, il est possible d'automatiser ce processus :
function créerMasque () { var nMask = 0, nFlag = 0, nLen = arguments.length > 32 ? 32 : arguments.length; for (nFlag; nFlag < nLen; nMask |= arguments[nFlag] << nFlag++); return nMask; } var masque1 = créerMasque(true, true, false, true); // 11, i.e.: 1011 var masque2 = créerMasque(false, false, true); // 4, i.e.: 0100 var masque3 = créerMasque(true); // 1, i.e.: 0001 // etc. console.log(masque1); // affiche 11, i.e.: 1011
Algorithme réciproque : obtenir un tableau de booléen à partir d'un masque
Si on souhaite créer un tableau de booléens à partir d'un masque, on pourra utiliser le code suivant :
function tableauMasque (nMask) { // nMask doit être compris entre -2147483648 et 2147483647 if (nMask > 0x7fffffff || nMask < -0x80000000) { throw new TypeError("tableauMasque - intervalle de valeur dépassé"); } for (var nShifted = nMask, aFromMask = []; nShifted; aFromMask.push(Boolean(nShifted & 1)), nShifted >>>= 1); return aFromMask; } var tableau1 = tableauMasque(11); var tableau2 = tableauMasque(4); var tableau3 = tableauMasque(1); console.log("[" + tableau1.join(", ") + "]"); // affiche "[true, true, false, true]", i.e.: 11, i.e.: 1011
On peut ainsi utiliser les deux algorithmes :
var test = 19; // un masque quelconque var résultat = créerMasque.apply(this, tableauMasque(test)); console.log(résultat); // 19
Pour l'exemple (car il existe la méthode Number.toString(2)
), on peut également modifier l'algorithme précédent pour créer une chaîne à partir de la représentation binaire d'un nombre :
function créerChaîneBinaire(nMask) { // nMask doit être compris entre -2147483648 et 2147483647 for (var nFlag = 0, nShifted = nMask, sMask = ""; nFlag < 32; nFlag++, sMask += String(nShifted >>> 31), nShifted <<= 1); return sMask; } var string1 = créerChaîneBinaire(11); var string2 = créerChaîneBinaire(4); var string3 = créerChaîneBinaire(1); console.log(string1); // affiche 00000000000000000000000000001011, i.e. 11
Spécifications
Spécification | Statut | Commentaires |
---|---|---|
ECMAScript 1st Edition (ECMA-262) | Standard | Définition initiale. |
ECMAScript 5.1 (ECMA-262) | Standard | Définis au sein de plusieurs sections de la spécification : Opérateur NON binaire, Opérateurs binaires de décalage, Opérateurs binaires |
ECMAScript 2015 (6th Edition, ECMA-262) | Standard | Définis au sein de plusieurs sections de la spécification : Opérateur NON binaire, Opérateurs binaires de décalage, Opérateurs binaires |
ECMAScript 2017 Draft (ECMA-262) | Projet | Defined in several sections of the specification: opérateur NON binaire, opérateurs binaires de décalage, opérateurs binaires |
Compatibilité des navigateurs
Fonctionnalité | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
NON binaire (~ ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
ET binaire (& ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
OU binaire (| ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
OU exclusif (XOR) binaire (^ ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
Décalage à gauche (<< ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
Décalage à droite (>> ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
Décalage à droite non-signé (>>> ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
Fonctionnalité | Android | Chrome pour Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
NON binaire (~ ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
ET binaire (& ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
OU binaire (| ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
OU exclusif (XOR) (^ ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
Décalage à gauche (<< ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
Décalage à droite (>> ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) | (Oui) |
Décalage à droite non-signé (>>> ) |
(Oui) | (Oui) | (Oui) | (Oui) | (Oui) | (Oui) |