2015-02-10 10 views
16

recente ho letto le specifiche golang e di fronte ad alcuni operatori interessanti:Differenza tra alcuni operatori "|", "^", "&", "& ^". Golang

& bitwise AND   integers 
| bitwise OR    integers 
^ bitwise XOR   integers 
&^ bit clear (AND NOT) integers 

Ho provato a giocare con lui, ma l'unico che ho capito è che "|" aggiungi interi e l'operatore "+" lavora anche con float, stringhe, ecc.

In cosa vengono utilizzati in pratica? Qualcuno potrebbe dare qualche spiegazione su questi 4 operatori sopra?

+2

Prendi un libro come "Codice" di Petzold per ottenere una conoscenza di base della rappresentazione binaria e dei fondamenti dell'informatica. –

risposta

30

Gli operatori bit a bit entrano in gioco quando si lavora con dati a livello di bit o bit.

Qui elenco una manciata di esempi che utilizzano operazioni bit con esempi di codice (in nessun ordine particolare):


1. Essi sono comuni e parte di molti algoritmi di crittografia e hash funzioni (ad es. MD5).

2. Essi sono spesso utilizzati se si vuole "salvare" lo spazio e si confezione più "bool" variabili in uno int per esempio, si assegna un po 'per ogni variabile bool. Devi usare operatori bit a bit per essere in grado di cambiare/leggere individualmente i bit.

Per esempio imballaggio 8 bit/Caccio in uno 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. Un'altra area è compressione dei dati in cui si desidera ottenere il massimo da una byte e utilizzare tutte le bit per archivia/recupera alcune informazioni (un po 'è l'unità di base di informazioni nell'informatica e nelle comunicazioni digitali).

4. Simile alla compressione, ma non proprio la stessa: bitstream. Viene anche utilizzato per risparmiare spazio in un flusso di dati non inviando byte completi ma piuttosto campi con lunghezza di bit arbitraria.

Ho scritto e pubblicato un pacchetto di Reader e Writer a livello di bit altamente ottimizzato, open source qui: github.com/icza/bitio. Vedrai un ampio uso di tutti i tipi di operazioni bit nelle sue fonti.

5. Un altro utilizzo pratico: test determinate proprietà di un (integer) numero. Conoscendo la rappresentazione binaria dei numeri interi (Two's complement) ci sono alcune caratteristiche dei numeri nella loro rappresentazione binaria. Per esempio un numero intero (in complemento a 2) è anche (può essere diviso per 2) se il bit più basso è 0:

func isEven(i int) bool { 
    return i&0x01 == 0 
} 

Testando i bit di un numero intero si può anche dire se si tratta di un potere di 2. Ad esempio se un numero positivo contiene solo uno 1 bit, allora è una potenza di 2 (ad esempio2 = 0x02 = 00000010b, 16 = 0x10 = 00010000 ma, ad esempio, 17 = 0x11 = 00010001, non alimentazione 2).

6.Molte procedure di codifica/decodifica utilizzano anche operazioni bit. Il più banale è il UTF-8 encoding che utilizza una codifica a lunghezza variabile per rappresentare i punti codice unicode (rune in Go) come sequenze di byte.
Una semplice variante di una codifica a lunghezza variabile potrebbe essere quella di utilizzare il bit più alto di un byte (8 ° o 7 ° se 0-indexed) per segnalare se sono necessari più byte per decodificare un numero e i 7 bit restanti sono sempre il dati "utili". È possibile verificare il più alto bit e "separato" i 7 bit utili in questo modo:

b := readOneByte() 
usefulBits := b & 0x7f 
hasMoreBytes := b & 0x80 != 0 

L'utile di utilizzare tale codifica a lunghezza variabile è che anche se si utilizza uint64 tipo in Go, che è di 8 byte in memoria , i numeri piccoli possono ancora essere rappresentati utilizzando meno byte (i numeri nell'intervallo 0..127 richiedono solo 1 byte!). Se i campioni che vuoi memorizzare o trasferire hanno molti piccoli valori, questo da solo può comprimere i dati a 1/8 = 12,5%. Il lato negativo è che i grandi numeri (che hanno bit anche nel byte più alto) useranno più di 8 byte. Se vale la pena dipende dall'euristica dei campioni.

X.E l'elenco potrebbe continuare ...


Si può vivere senza conoscere/utilizzare gli operatori bit a bit in Go (e in molti altri linguaggi di programmazione)? La risposta è si. Ma se li conosci, a volte possono renderti la vita più facile e i tuoi programmi più efficienti.

Se vuoi saperne di più sull'argomento, leggi l'articolo di Wikipedia: Bitwise operation e su Google il termine "Tutorial Operatori bitwise", ci sono molti buoni articoli.

+0

Grazie! Davvero una buona risposta. Potresti suggerire il libro, che spieghi alcune nozioni di base della programmazione "di basso livello" per principianti come me? (senza approfondire in termini troppo tecnici e matematici) –

+1

@TimurFayzrakhmanov Basta google (il termine _ "tutorial bitwise operatori" _), ci sono molti buoni tutorial su internet. La maggior parte sono specifici della lingua, ma più o meno si applicano a tutti i linguaggi di programmazione. Ecco una buona trovata in 1 minuto su google: [Understanding Bitwise Operators] (http://code.tutsplus.com/articles/understanding-bitwise-operators--active-11301). Leggi anche l'articolo di wikipedia: [Operazione bitwise] (http://en.wikipedia.org/wiki/Bitwise_operation) – icza

+0

capito! grazie ancora!) –

13

Per quello che tecnicamente controlli anche il commento in questo

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) 
} 

View it on the playground

prega di notare che ho dato due esempi di | per dimostrare che non è davvero aggiunta come 1 + 5.

Per quanto riguarda gli usi pratici, sono sicuro che altri potrebbero commentare con altri esempi, ma un uso comune è creare una maschera di bit di flag per qualcosa come un sistema di autorizzazione.

Problemi correlati