Comprendre les opérateurs au niveau des bits

Les opérateurs au niveau du bit sont des opérateurs étranges qui paraissent difficiles à comprendre… mais plus maintenant! Cet article facile à suivre vous aidera à comprendre ce qu’ils sont et comment les utiliser, avec quelques exemples pratiques pour vous montrer quand et pourquoi vous en avez besoin..


introduction

Les opérateurs au niveau du bit sont des opérateurs (comme +, *, &&, etc.) qui fonctionnent sur ints et des allusions au niveau binaire. Cela signifie qu'ils regardent directement les chiffres binaires ou les bits d'un entier. Tout cela semble effrayant, mais en réalité, les opérateurs au niveau des bits sont assez faciles à utiliser et très utiles.!

Toutefois, il est important que vous compreniez les nombres binaires et les nombres hexadécimaux. Si vous ne le faites pas, consultez cet article, il vous aidera vraiment! Vous trouverez ci-dessous une petite application qui vous permettra d’essayer les différents opérateurs au niveau des bits..

Ne vous inquiétez pas si vous ne comprenez pas encore ce qui se passe, tout sera bientôt clair…


Reconnaître les opérateurs au niveau des bits

Jetons un coup d'œil aux opérateurs au niveau des bits fournis par AS3. De nombreux autres langages sont assez similaires (par exemple, JavaScript et Java ont des opérateurs pratiquement identiques):

  • & (bitwise AND)
  • | (bitwise OU)
  • ~ (bitwise PAS)
  • ^ (bitor XOR)
  • << (bitwise left shift)
  • >> (décalage droit au niveau du bit)
  • >>> (décalage droit non signé au niveau du bit)
  • & = (affectation AND au niveau du bit)
  • | = (affectation OU au niveau du bit)
  • ^ = (attribution XOR au niveau du bit)
  • <<= (bitwise left shift and assignment)
  • >> = (décalage droit au niveau du bit et affectation)
  • >>> = (décalage droit et affectation non signées au niveau du bit)

Voici quelques éléments à retenir: Premièrement, certains opérateurs au niveau des bits se ressemblent beaucoup aux opérateurs que vous avez utilisés auparavant (& vs. &&, | vs. ||). C'est parce qu'ils sont un peu similaire.

Deuxièmement, la plupart des opérateurs au niveau du bit viennent avec formulaire d'affectation composée d'eux-mêmes. C’est la même chose que vous pouvez utiliser + et + =, - et - =, etc..


L'opérateur

En haut en premier: l'opérateur AND au niveau des bits, &. Un avertissement rapide cependant: normalement, ints et des allusions occupe 4 octets ou 32 bits d’espace. Cela signifie que chaque int ou uint est stocké sous forme de 32 chiffres binaires. Par souci de ce tutoriel, nous prétendons parfois que ints et des allusions n'occupe qu'un octet et n'a que 8 chiffres binaires.

L'opérateur & compare chaque chiffre binaire de deux nombres entiers et renvoie un nouveau nombre entier, avec un 1 lorsque les deux nombres ont un 1 et un 0 partout ailleurs. Un diagramme vaut mille mots, alors en voici un pour éclaircir les choses. C'est représenter 37 et 23, qui est égal à 5.

Notez comment chaque chiffre binaire de 37 et 23 est comparé, et le résultat a un 1 partout où 37 et 23 ont un 1, et le résultat a un 0 sinon.

Une façon courante de penser aux chiffres binaires est la suivante: vrai ou faux. C'est-à-dire que 1 équivaut à vrai et 0 équivaut à faux. Cela rend l'opérateur & plus logique.

Quand on compare deux booléens, on fait normalement boolean1 && boolean2. Cette expression n’est vraie que si les deux booléen1 et booléen2 sont vrai. De la même manière, entier1 & entier2 est équivalent, l'opérateur & ne produisant un 1 que lorsque les deux chiffres binaires de nos deux entiers sont 1.

Voici un tableau qui représente cette idée:

L’opérateur & sert rarement à vérifier si un nombre est pair ou impair. Pour les nombres entiers, nous pouvons simplement vérifier le bit le plus à droite (également appelé bit le moins significatif) pour déterminer si le nombre entier est impair ou pair. En effet, lors de la conversion en base 10, le bit le plus à droite représente 20 ou 1. Lorsque le bit le plus à droite est 1, nous savons que notre nombre est impair puisque nous ajoutons 1 à un groupe de puissances de deux qui sera toujours pair. Lorsque le bit le plus à droite est 0, nous savons que notre nombre sera pair, car il consiste simplement à additionner une série de nombres pairs..

Voici un exemple:

 var randInt: int = int (Math.random () * 1000); if (randInt & 1) trace ("nombre impair.");  else trace ("Nombre pair."); 

Sur mon ordinateur, cette méthode était environ 66% plus rapide que l’utilisation de randInt% 2 pour vérifier les nombres pairs et impairs. C'est un coup de pouce pour la performance!


Le | Opérateur

La prochaine étape est l'opérateur OU au niveau du bit, | Comme vous l'avez peut-être deviné, le | l'opérateur est à la || l'opérateur comme l'opérateur & est à l'opérateur &&. Le | opérateur compare chaque chiffre binaire sur deux entiers et redonne un 1 si non plus d'entre eux sont 1. Encore une fois, cela est similaire à la || opérateur avec booléens.

Jetons un coup d'oeil au même exemple qu'auparavant, sauf que nous utilisons maintenant le | opérateur à la place de l'opérateur &. Nous faisons maintenant 37 | 23 ce qui équivaut à 55:


Drapeaux: utilisation du & et | Les opérateurs

Nous pouvons profiter de la & et | opérateurs pour nous permettre de passer plusieurs options à une fonction dans un seul int.

Jetons un coup d'oeil à une situation possible. Nous construisons une classe de fenêtre pop-up. Au bas de la liste, nous pouvons avoir un bouton Oui, Non, OK ou Annuler, ou toute combinaison de ceux-ci - comment devrions-nous procéder? Voici le moyen le plus difficile:

 classe publique PopupWindow étend Sprite // Variables, constructeur, etc… public statique void showPopup (yesButton: Boolean, noButton: Boolean, okayButton: Boolean, cancelButton: Boolean) if (yesButton) // bouton YES si (noButton ) // ajouter le bouton NON // et ainsi de suite pour le reste des boutons

Est-ce horrible? Non, mais il est mauvais, si vous êtes programmeur, de devoir rechercher l'ordre des arguments chaque fois que vous appelez la fonction. C'est également agaçant - par exemple, si vous souhaitez uniquement afficher le bouton Annuler, vous devez définir tous les autres paramètres. Booléens à faux.

Utilisons ce que nous avons appris sur & et | pour faire une meilleure solution:

 classe publique PopupWindow étend Sprite public static const YES: int = 1; public statique const NO: int = 2; public statique const OKAY: int = 4; public statique const CANCEL: int = 8; public statique void showPopup (buttons: int) if (buttons & YES) // ajoute le bouton YES if (buttons & NO) // ajoute le bouton NO

Comment un programmeur appelle-t-il la fonction pour afficher les boutons Oui, Non et Annuler? Comme ça:

 PopupWindow.show (PopupWindow.YES | PopupWindow.NO | PopupWindow.CANCEL);

Que se passe-t-il? Il est important de noter que nos constantes dans le deuxième exemple sont toutes des puissances de deux. Donc, si nous regardons leurs formes binaires, nous remarquerons qu’ils ont tous un chiffre égal à 1 et le reste égal à 0. En fait, ils ont chacun un chiffre différent égal à 1. Cela signifie que peu importe la façon dont nous combinons les avec |, chaque combinaison nous donnera un numéro unique. En regardant les choses différemment, résultat de notre | déclaration sera un nombre binaire avec un 1 partout où nos options avaient un 1.

Pour notre exemple actuel, nous avons PopupWindow.YES | PopupWindow.NO | PopupWindow.CANCEL ce qui équivaut à 1 | 2 | 8 qui réécrit en binaire est 00000001 | 00000010 | 00001000 ce qui nous donne un résultat de 00001011.

Maintenant, dans notre showPopup () fonction, nous utilisons & pour vérifier quelles options ont été transmises. Par exemple, lorsque nous vérifions boutons et OUI, tous les bits de YES sont égaux à 0 sauf le plus à droite. Nous vérifions donc essentiellement si le bit le plus à droite dans les boutons est un 1 ou non. Si c'est, boutons et OUI ne sera pas égal à 0 et quoi que ce soit dans l'instruction if sera exécuté. Inversement, si le bit le plus à droite des boutons est 0, boutons et OUI sera égal à 0, et l'instruction if ne sera pas exécutée.


Le ~ opérateur

L'opérateur bitwise NOT est légèrement différent des deux que nous avons examinés jusqu'à présent. Au lieu de prendre un entier de chaque côté, il prend un entier seulement après. C'est comme le! opérateur, et, sans surprise, il fait la même chose. En fait, juste comme! retourne un booléen de vrai à faux ou inversement, l'opérateur ~ inverse chaque chiffre binaire en un entier: de 0 à 1 et de 1 à 0:

Un exemple rapide. Disons que nous avons le nombre entier 37, ou 00100101. ~ 37 est alors 11011010. Quelle est la valeur de base 10 de cela? Bien…


Complément à deux, uint contre. int, et plus!

Maintenant, le plaisir commence! Nous allons examiner de plus près les nombres binaires sur un ordinateur. Commençons par le uint. Comme mentionné précédemment, un uint est typiquement de 4 octets ou 32 bits de long, ce qui signifie qu'il a 32 chiffres binaires. Cela est facile à comprendre: pour obtenir la valeur de base 10, nous convertissons simplement le nombre en base 10 régulièrement. Nous aurons toujours un nombre positif.

Mais qu'en est-il du int? Il utilise également 32 bits, mais comment stocke-t-il les nombres négatifs? Si vous avez deviné que le premier chiffre est utilisé pour stocker le signe, vous êtes sur le bon chemin. Jetons un coup d'oeil au complément à deux système pour stocker des nombres binaires. Bien que nous n'allions pas entrer dans tous les détails ici, un système de complément à deux est utilisé car il facilite l'arithmétique binaire..

Pour trouver le complément à deux d'un nombre binaire, nous retournons simplement tous les bits (c'est-à-dire ce que fait l'opérateur ~) et ajoutons un au résultat. Essayons cela une fois:

Nous définissons ensuite notre résultat comme la valeur -37. Pourquoi faire ce processus compliqué et ne pas simplement retourner le tout premier bit et appeler cela -37?

Eh bien, prenons une expression simple 37 + -37. Nous savons tous que cela devrait être égal à 0, et lorsque nous ajoutons le 37 à son complément à deux, nous obtenons ce qui suit:

Notez que puisque nos entiers ne contiennent que huit chiffres binaires, le 1 de notre résultat est supprimé et nous nous retrouvons avec 0, comme il se doit..

Pour récapituler, pour trouver le négatif d'un nombre, nous prenons simplement son complément à deux. Nous pouvons le faire en inversant tous les bits et en ajoutant un.

Voulez-vous essayer cela vous-même? Ajouter trace (~ 37 + 1); dans un fichier AS3, puis compilez-le et exécutez-le. Vous verrez que -37 est imprimé, comme il se doit.

Il existe également un petit raccourci pour le faire à la main: en partant de la droite, continuez à gauche jusqu'à atteindre le 1. Inversez tous les bits à gauche de cette première 1.

Lorsque nous examinons un nombre binaire signé (en d’autres termes, un nombre qui peut être négatif, un int pas un uint), nous pouvons regarder le chiffre le plus à gauche pour dire s'il est négatif ou positif. S'il s'agit d'un 0, le nombre est positif et nous pouvons convertir en base 10 simplement en calculant sa valeur en base 10. Si le bit le plus à gauche est 1, le nombre est négatif. Nous utilisons donc le complément à deux du nombre pour obtenir sa valeur positive, puis ajoutons simplement un signe négatif..

Par exemple, si nous avons 11110010, nous savons que c'est un nombre négatif. Nous pouvons trouver son complément à deux en retournant tous les chiffres à gauche de la plus à droite 1, ce qui nous donne 00001110. Cela équivaut à 13, nous savons donc que 11110010 est égal à -13..


L'opérateur ^

Nous revenons aux opérateurs au niveau des bits, et l'opérateur XOR au niveau des bits est le suivant. Il n'y a pas d'opérateur booléen équivalent à celui-ci.

L'opérateur ^ est similaire à & & | opérateurs en ce qu'il prend une int ou uint sur les deux côtés. Lorsqu'il calcule le nombre obtenu, il compare à nouveau les chiffres binaires de ces nombres. Si l'un ou l'autre est un 1, il insérera un 1 dans le résultat, sinon il insérera un 0. C'est là que le nom XOR, ou "exclusif ou" provient de.

Jetons un coup d'oeil à notre exemple habituel:

L'opérateur ^ a des utilisations - il est particulièrement utile pour basculer les chiffres binaires - mais nous ne couvrirons aucune application pratique dans cet article.


le << Operator

Nous sommes maintenant sur les opérateurs de décalage de bits, en particulier l'opérateur de décalage gauche au niveau du bit ici.

Ceux-ci fonctionnent un peu différemment qu'avant. Au lieu de comparer deux nombres entiers comme &, | et ^, ces opérateurs décalent un entier. Sur le côté gauche de l'opérateur se trouve le nombre entier qui est déplacé, et sur la droite, le nombre de points à modifier. Ainsi, par exemple, 37 << 3 is shifting the number 37 to the left by 3 places. Of course, we're working with the binary representation of 37.

Jetons un coup d'oeil à cet exemple (rappelez-vous, nous allons simplement prétendre que les entiers n'ont que 8 bits au lieu de 32). Ici nous avons le numéro 37 assis sur son beau bloc de mémoire de 8 bits de large.

Très bien, faisons glisser tous les chiffres vers la gauche de 3, comme 37 << 3 ferait:

Mais maintenant, nous avons un petit problème - que faisons-nous avec les 3 bits ouverts de la mémoire où nous avons déplacé les chiffres de?

Bien sûr! Toutes les zones vides sont simplement remplacées par des 0. Nous nous retrouvons avec 00101000. Et c'est tout ce qu'il y a à gauche vers le décalage des bits. Gardez à l'esprit que Flash pense toujours que le résultat d'un décalage de bits à gauche est un int, pas un uint. Donc si vous avez besoin d'un uint pour une raison quelconque, vous devrez le jeter à un uint comme ça: uint (37 << 3). Cette diffusion ne change en réalité aucune des informations binaires, mais la façon dont Flash l'interprète (le complément des deux entiers).

Une caractéristique intéressante du décalage de bits de gauche est que cela revient à multiplier un nombre par deux pour la puissance shift-montante. Alors, 37 << 3 == 37 * Math.pow(2,3) == 37 * 8. Si vous pouvez utiliser le décalage gauche au lieu de Math.pow, vous verrez une énorme augmentation de la performance.

Vous avez peut-être remarqué que le nombre binaire avec lequel nous nous sommes retrouvés n'était pas égal à 37 * 8. Cela vient de notre utilisation de seulement 8 bits de mémoire pour les entiers; Si vous l'essayez en ActionScript, vous obtiendrez le résultat correct. Ou essayez-le avec la démo en haut de la page!


Le >> opérateur

Maintenant que nous comprenons le décalage de bits de gauche, le suivant, le décalage de droite, sera facile. Tout glisse à droite le montant que nous spécifions. La seule petite différence est ce que les bits vides sont remplis.

Si nous commençons avec un nombre négatif (un nombre binaire où le bit le plus à gauche est un 1), tous les espaces vides sont remplis avec un 1. Si nous commençons avec un nombre positif (où le bit le plus à gauche, ou le plus significatif est un 0), tous les espaces vides sont remplis d'un 0. Encore une fois, tout revient au complément à deux.

Bien que cela semble compliqué, cela ne fait que conserver le signe du nombre avec lequel nous commençons. Alors -8 >> 2 == -2 tandis que 8 >> 2 == 2. Je recommanderais d'essayer ceux-ci sur papier vous-même.

Puisque >> est le contraire de <<, it's not surprising that shifting a number to the right is the same as dividing it by 2 to the power of shiftAmount. You may have noticed this from the example above. Again, if you can use this to avoid calling Math.pow, vous obtiendrez une amélioration significative des performances.


Le >>> opérateur

Notre dernier opérateur au niveau des bits est le décalage droit non signé au niveau des bits. Cela ressemble beaucoup au décalage droit au niveau du bit habituel, sauf que tous les bits vides à gauche sont remplis avec des 0. Cela signifie que le résultat de cet opérateur est toujours un entier positif et qu'il traite toujours l'entier déplacé comme un entier non signé. Nous ne passerons pas en revue un exemple de cela dans cette section, mais nous en verrons l'usage très prochainement..


Utilisation d'opérateurs binaires pour travailler avec des couleurs

L'une des utilisations les plus pratiques des opérateurs au niveau du bit dans Actionscript 3 consiste à utiliser des couleurs, stockées généralement sous la forme des allusions.

Le format standard des couleurs consiste à les écrire en hexadécimal: 0xAARRGGBB - chaque lettre représente un chiffre hexadécimal. Ici, les deux premiers chiffres hexadécimaux, qui sont équivalents aux huit premiers chiffres binaires, représentent notre alpha, ou notre transparence. Les huit bits suivants représentent la quantité de rouge dans notre couleur (donc un entier compris entre 0 et 255), les huit suivants, la quantité de vert et les huit derniers bits représentent la quantité de bleu dans notre couleur..

Sans opérateurs au niveau des bits, il est extrêmement difficile de travailler avec des couleurs dans ce format - mais avec elles, c'est facile!

Défi 1: Trouver la quantité de bleu dans une couleur: En utilisant l'opérateur &, essayez de trouver la quantité de bleu dans une couleur arbitraire.

 fonction publique findBlueComponent (color: uint): uint // Votre code ici! 

Nous avons besoin d’un moyen pour «effacer» ou masquer toutes les autres données Couleur et juste avoir le composant bleu à gauche. C'est facile, en fait! Si on prend couleur & 0x000000FF - ou, écrit plus simplement, couleur & 0xFF - nous nous retrouvons avec seulement la composante bleue.

Comme vous pouvez le voir ci-dessus et que vous avez appris dans la description de l'opérateur &, tout chiffre binaire & 0 sera toujours égal à 0, tandis que tout chiffre binaire & 1 conservera sa valeur. Donc, si nous masquons notre couleur par 0xFF qui ne contient que des 1 où se trouve la composante bleue de notre couleur, nous nous retrouvons avec uniquement la composante bleue.

Défi 2: Trouver la quantité de rouge dans une couleur: En utilisant deux opérateurs au niveau des bits, essayez de trouver la quantité de rouge dans une couleur arbitraire.

 fonction publique findRedComponent (color: uint): uint // Votre code ici! 

Nous avons en fait deux solutions à ce problème. On serait return (color & 0xFF0000) >> 16; et l'autre serait return (color >> 16) & 0xFF;

C'est très similaire au défi 1, sauf que nous devons changer notre réponse à un moment donné..

Défi 3: Trouver la transparence d'une couleur: En utilisant un seul opérateur au niveau du bit, essayez de trouver l’alpha d’une couleur (un entier compris entre 0 et 255).

 fonction publique findAlphaComponent (color: uint): uint // Votre code ici! 

Celui-ci est un peu plus compliqué. Nous devons faire attention au type d'opérateur de droite que nous choisissons. Parce que nous travaillons avec les chiffres les plus à gauche d'un uint, nous voulons utiliser >>> opérateur. Donc, notre réponse est simplement couleur de retour >>> 24;.

Défi final: créer une couleur à partir de ses composants: En utilisant le << and | operators, take the components of a color and merge them in to one uint.

 fonction publique createColor (a: uint, r: uint, g: uint, b: uint): uint // Votre code ici! 

Ici, nous devons déplacer chaque composant à sa position correcte, puis les fusionner. Nous voulons que Flash le traite comme un entier non signé, nous le lançons donc dans un uint: return uint ((a << 24) | (r << 16) | (g << 8) | b);


Opérateurs Compound

Vous avez peut-être remarqué que j'ai négligé d'expliquer les opérateurs composés au niveau des bits. Imaginons que nous ayons un entier x. ensuite, x = x & 0xFF est le même que x & = 0xFF, x = x | 256 est le même que x | = 256, et ainsi de suite pour le reste des opérateurs de composés.


Conclusion

Merci d'avoir lu cet article! J'espère que vous comprenez maintenant les opérateurs au niveau des bits et que vous pouvez les utiliser dans votre code AS3 (ou dans de nombreuses autres langues!). Comme toujours, si vous avez des questions ou des commentaires, veuillez les laisser ci-dessous..