Différence entre certains opérateurs "|", "^", "&", "&^". Golang
récemment j'ai lu golang spécification et face à certains opérateurs intéressants:
& bitwise AND integers
| bitwise OR integers
^ bitwise XOR integers
&^ bit clear (AND NOT) integers
j'ai essayé de jouer avec, mais le seul que j'ai compris est que "|" ajouter des entiers et "+" opérateur fonctionnent en plus avec des flotteurs, des chaînes, etc.
à quoi servent-ils dans la pratique? Quelqu'un pourrait-il donner quelques explications sur ces 4 opérateurs ci-dessus?
2 réponses
les opérateurs Bitwise entrent en jeu lorsque vous devez travailler avec octets ou de bits de données.
Voici une liste d'exemples d'opérations utilisant des bits avec des échantillons de code (dans aucun ordre particulier):
1. ils sont communs et font partie de nombreux algorithmes dans cryptographie et fonctions de hachage (e.g. MD5).
2. ils sont aussi souvent utilisés si vous voulez "sauver" l'espace et vous pack de plusieurs "bool" variables en un seul int
par exemple, vous assignez un bit à chaque variable bool. Vous devez utiliser des opérateurs bitwise pour pouvoir modifier/lire individuellement les bits.
par exemple empaqueter 8 bits / bools dans un int
:
flags := 0x00 // All flags are 0
flags |= 0x02 // Turn the 2nd bit to 1 (leaving rest unchanged)
flags |= 0xff // Turn 8 bits (0..7) to 1
flags &= 0xfe // Set the lowest bit to 0 (leaving rest unchanged)
istrue := flags&0x04 != 0 // Test if 3rd bit is 1
3. une compression de données où vous voulez obtenir les la plupart hors d'un byte
et d'utiliser tous ses bits pour stocker/récupérer quelques infos (un bit est l'unité d'information de base en informatique et communications numériques).
4. semblable à la compression mais pas tout à fait le même: chaînes de bits. Il est également utilisé pour économiser de l'espace dans un flux de données en n'envoyant pas des octets complets, mais plutôt des champs ayant une longueur de bits arbitraire.
j'ai écrit et publié un logiciel de lecture et D'écriture de niveau bit très optimisé, disponible ici: github.com/icza/bitio. Vous verrez l'utilisation extensive de toutes sortes d'opérations sur les bits dans ses sources.
5. une Autre pratique d'utilisation: tester certaines propriétés d'un (entier) nombre. Connaître la représentation binaire des nombres entiers ( le complément de Two) il y a certaines caractéristiques de nombres dans leur représentation binaire. Par exemple un nombre entier (dans le complément de 2) est même (peut être divisé par 2) si le bit le plus bas est 0:
func isEven(i int) bool {
return i&0x01 == 0
}
En testant les bits d'un entier, vous pouvez aussi dire si c'est une puissance de 2. Par exemple, si un nombre positif ne contient qu'un seul 1
bit, alors que c'est une puissance de 2 (par exemple,2 = 0x02 = 00000010b
,16 = 0x10 = 00010000
mais par exemple 17 = 0x11 = 00010001
pas de puissance de 2).
6. de nombreuses procédures d'encodage / décodage utilisez aussi les opérations de bits. Le plus trivial est le UTF-8 l'encodage qui utilise un encodage de longueur variable pour représenter les points de code unicode (rune
en Aller) comme les séquences d'octets.
Une variation simple d'un encodage de longueur variable pourrait être d'utiliser le bit le plus élevé d'un octet (8ème ou 7ème si 0-indexé) pour signaler si plus d'octets sont nécessaires pour décoder un nombre, et les 7 bits restants sont toujours les données "utiles". Vous pouvez tester le bit le plus élevé et "séparer" les 7 bits utiles comme ceci:
b := readOneByte()
usefulBits := b & 0x7f
hasMoreBytes := b & 0x80 != 0
Le bénéfice de l'aide un tel encodage de longueur variable est que même si vous utilisez uint64
tapez Go qui est de 8 octets en mémoire, les petits nombres peuvent encore être représentés en utilisant moins d'octets (nombres dans la gamme 0..127
seulement besoin de 1 octet!). Si les échantillons que vous voulez stocker ou transférer ont beaucoup de petites valeurs, cela seul peut compresser les données à 1/8ème = 12,5 %. Le côté négatif est que les grands nombres (qui ont des bits même dans le octet le plus élevé) utiliseront plus de 8 octets. Si ça vaut le coup dépend de l'heuristique de la échantillon.
X.Et la liste continue...
pouvez-vous vivre sans connaître/utiliser des opérateurs bitwise dans Go (et dans beaucoup d'autres langages de programmation)? La réponse est oui. Mais si vous les connaissez, ils peuvent parfois vous faciliter la vie et rendre vos programmes plus efficaces.
si vous voulez en savoir plus sur le sujet, lisez L'article de Wikipedia:opération au niveau du Bit et google le terme "Bitwise" Tutoriel opérateurs", Il ya beaucoup de bons articles.
Pour ce qu'ils techniquement le faire vérifier les commentaires dans ce
package main
import "fmt"
func main() {
// Use bitwise OR | to get the bits that are in 1 OR 2
// 1 = 00000001
// 2 = 00000010
// 1 | 2 = 00000011 = 3
fmt.Println(1 | 2)
// Use bitwise OR | to get the bits that are in 1 OR 5
// 1 = 00000001
// 5 = 00000101
// 1 | 5 = 00000101 = 5
fmt.Println(1 | 5)
// Use bitwise XOR ^ to get the bits that are in 3 OR 6 BUT NOT BOTH
// 3 = 00000011
// 6 = 00000110
// 3 ^ 6 = 00000101 = 5
fmt.Println(3 ^ 6)
// Use bitwise AND & to get the bits that are in 3 AND 6
// 3 = 00000011
// 6 = 00000110
// 3 & 6 = 00000010 = 2
fmt.Println(3 & 6)
// Use bit clear AND NOT &^ to get the bits that are in 3 AND NOT 6 (order matters)
// 3 = 00000011
// 6 = 00000110
// 3 &^ 6 = 00000001 = 1
fmt.Println(3 &^ 6)
}
veuillez noter que j'ai donné deux exemples de |
pour montrer qu'il n'est vraiment plus comme 1 + 5
.
en ce qui concerne les utilisations pratiques, je suis sûr que d'autres pourraient commenter avec plus d'exemples, mais une utilisation courante est de créer un bitmask de drapeaux pour quelque chose comme un système de permission.