Cosa sono gli operatori bit a bit?


130

Sono una persona che scrive codice solo per divertimento e non l'ho mai approfondito in un ambiente accademico o professionale, quindi cose come questi operatori bit per bit mi sfuggono davvero.

Stavo leggendo un articolo su JavaScript, che apparentemente supporta operazioni bit per bit. Continuo a vedere questa operazione menzionata in alcuni punti e ho provato a leggere per capire di cosa si tratta esattamente, ma non riesco proprio a capirla. Allora cosa sono? Esempi chiari sarebbero fantastici! : D

Solo qualche altra domanda: quali sono alcune applicazioni pratiche delle operazioni bit a bit? Quando potresti usarli?


2
Per ulteriori domande, potresti voler aggiungere una nuova domanda SO e fare riferimento a questa. Probabilmente otterrai una serie migliore di risposte in questo modo.
Greg Hewgill,

Risposte:


187

Dal momento che nessuno ha affrontato l'argomento del perché questi sono utili:

Uso molto le operazioni bit per bit quando lavoro con le bandiere. Ad esempio, se si desidera passare una serie di flag a un'operazione (ad esempio File.Open(), con la modalità di lettura e la modalità di scrittura entrambe abilitate), è possibile passarli come un singolo valore. Ciò si ottiene assegnando ad ogni possibile flag il proprio bit in un bitset (byte, short, int o long). Per esempio:

 Read: 00000001
Write: 00000010

Quindi, se si desidera passare in lettura e scrittura, si passerà (READ | WRITE) che quindi combina i due in

00000011

Che poi può essere decifrato dall'altra parte come:

if ((flag & Read) != 0) { //...

che controlla

00000011 &
00000001

che ritorna

00000001

che non è 0, quindi il flag specifica READ.

Puoi usare XOR per attivare o disattivare vari bit. L'ho usato quando ho usato una bandiera per specificare input direzionali (Su, Giù, Sinistra, Destra). Ad esempio, se uno sprite si muove in orizzontale e voglio che si giri:

     Up: 00000001
   Down: 00000010
   Left: 00000100
  Right: 00001000
Current: 00000100

Ho semplicemente XOR il valore corrente con (SINISTRA | DESTRA) che disattiva SINISTRA e DESTRA, in questo caso.

Bit Shifting è utile in diversi casi.

x << y

equivale a

x * 2 y

se devi moltiplicare rapidamente per una potenza di due, ma fai attenzione a spostare un 1 bit nel bit superiore - questo rende il numero negativo a meno che non sia senza segno. È anche utile quando si ha a che fare con dati di dimensioni diverse. Ad esempio, leggendo un numero intero da quattro byte:

int val = (A << 24) | (B << 16) | (C << 8) | D;

Supponendo che A sia il byte più significativo e D il minimo. Sarebbe finito come:

A = 01000000
B = 00000101
C = 00101011
D = 11100011
val = 01000000 00000101 00101011 11100011

I colori vengono spesso memorizzati in questo modo (con il byte più significativo ignorato o utilizzato come Alpha):

A = 255 = 11111111
R = 21 = 00010101
G = 255 = 11111111
B = 0 = 00000000
Color = 11111111 00010101 11111111 00000000

Per trovare nuovamente i valori, basta spostare i bit verso destra fino a quando non è in fondo, quindi mascherare i rimanenti bit di ordine superiore:

Int Alpha = Color >> 24
Int Red = Color >> 16 & 0xFF
Int Green = Color >> 8 & 0xFF
Int Blue = Color & 0xFF

0xFFè lo stesso di 11111111. Quindi essenzialmente, per Red, faresti questo:

Color >> 16 = (filled in 00000000 00000000)11111111 00010101  (removed 11111111 00000000)
00000000 00000000 11111111 00010101 &
00000000 00000000 00000000 11111111 =
00000000 00000000 00000000 00010101 (The original value)

x << n, quindi n deve essere nella forma di 2 ^ valore?
Ahmed C

28

Vale la pena notare che le tabelle di verità a bit singolo elencate come altre risposte funzionano solo su uno o due bit di input alla volta. Cosa succede quando si usano numeri interi, come:

int x = 5 & 6;

La risposta sta nell'espansione binaria di ciascun input:

  5 = 0 0 0 0 0 1 0 1
& 6 = 0 0 0 0 0 1 1 0
---------------------
      0 0 0 0 0 1 0 0

Ogni coppia di bit in ciascuna colonna viene eseguita attraverso la funzione "AND" per fornire il bit di uscita corrispondente nella riga inferiore. Quindi la risposta all'espressione precedente è 4. La CPU ha eseguito (in questo esempio) 8 operazioni separate "AND" in parallelo, una per ogni colonna.

Lo dico perché ricordo ancora di avere questo "AHA!" momento in cui ho appreso questo molti anni fa.


Wow, ora ha molto più senso. Sembrava molto più complicato di quanto sembra. Grazie. Non sono sicuro quale scegliere come risposta giusta in quanto ce ne sono molte di buone, e non posso votare così .. grazie
fai clic su

27

Gli operatori bit a bit sono operatori che lavorano un po 'alla volta.

AND è 1 solo se entrambi i suoi ingressi sono 1.

OR è 1 se uno o più dei suoi input sono 1.

XOR è 1 solo se esattamente uno dei suoi ingressi è 1.

NOT è 1 solo se i suoi input sono 0.

Questi possono essere meglio descritti come tabelle di verità. Le possibilità di input sono in alto e a sinistra, il bit risultante è uno dei quattro valori (due nel caso di NOT poiché ha solo un input) mostrati all'intersezione dei due input.

AND|0 1      OR|0 1
---+----    ---+----
  0|0 0       0|0 1
  1|0 1       1|1 1

XOR|0 1     NOT|0 1
---+----    ---+---
  0|0 1        |1 0
  1|1 0

Un esempio è se vuoi solo i 4 bit inferiori di un numero intero, tu AND con 15 (binario 1111) quindi:

    203: 1100 1011
AND  15: 0000 1111
------------------
 IS  11: 0000 1011

16

Questi sono gli operatori bit a bit, tutti supportati in JavaScript:

  • op1 & op2- L' ANDoperatore confronta due bit e genera un risultato di 1 se entrambi i bit sono 1; in caso contrario, restituisce 0.

  • op1 | op2- L' ORoperatore confronta due bit e genera un risultato di 1 se i bit sono complementari; in caso contrario, restituisce 0.

  • op1 ^ op2- L' EXCLUSIVE-ORoperatore confronta due bit e restituisce 1 se uno dei bit è 1 e fornisce 0 se entrambi i bit sono 0 o 1.

  • ~op1- L' COMPLEMENToperatore viene utilizzato per invertire tutti i bit dell'operando.

  • op1 << op2- L' SHIFT LEFToperatore sposta i bit a sinistra, scarta il bit più a sinistra e assegna al bit più a destra un valore di 0. Ogni spostamento a sinistra moltiplica efficacemente op1 per 2.

  • op1 >> op2- L' SHIFT RIGHToperatore sposta i bit a destra, scarta il bit all'estrema destra e assegna al bit più a sinistra un valore di 0. Ogni spostamento a destra divide efficacemente op1 a metà. Il bit di segno più a sinistra viene conservato.

  • op1 >>> op2- L' operatore SHIFT RIGHT- ZERO FILLsposta i bit a destra, scarta il bit all'estrema destra e assegna al bit più a sinistra un valore di 0. Ogni spostamento a destra divide efficacemente op1 a metà. Il bit del segno più a sinistra viene scartato.


"se i bit sono complementari" - waht?
Andrey Tyukin,

@AndreyTyukin due bit sono complementari se uno è 1 e l'altro è 0.
Jeff Hillman

@JeffHillman Secondo la tua descrizione nel commento, 1 e 1 non sono "complementari". Quindi non mi è chiaro perché 1 | 1dia 1e no 0, e come |dovrebbe essere diverso da ^. Ho dovuto usare questo Q / A come obiettivo duplicato pochi giorni fa e desideravo che dopo 10 anni si potesse avere un duplicato canonico più chiaro per questo tipo di domande.
Andrey Tyukin,

4

Per scomporlo un po 'di più, ha molto a che fare con la rappresentazione binaria del valore in questione.

Ad esempio (in decimale):
x = 8
y = 1

verrebbe fuori (in binario):
x = 1000
y = 0001

Da lì, è possibile eseguire operazioni di calcolo come 'e' o 'o'; in questo caso:
x | y =
1000 
0001 |
------
1001

oppure ... 9 in decimale

Spero che questo ti aiuti.


|sono operazioni OR?
Si8

Per qualche ragione questo ha avuto più senso per me. Ancora non sono sicuro della x | y = 1000 0001 |parte
samayo

4

Quando viene citato il termine "bit per bit", a volte si chiarisce che non è un operatore "logico".

Ad esempio in JavaScript, gli operatori bit a bit considerano i loro operandi come una sequenza di 32 bit (zero e uno) ; nel frattempo, gli operatori logici vengono generalmente utilizzati con valori booleani (logici) ma possono funzionare con tipi non booleani.

Prendi ad esempio expr1 && expr2.

Restituisce expr1 se può essere convertito in false; in caso contrario, restituisce expr2. Pertanto, se utilizzato con valori booleani, && restituisce vero se entrambi gli operandi sono veri; in caso contrario, restituisce false.

a = "Cat" && "Dog"     // t && t returns Dog
a = 2 && 4     // t && t returns 4

Come altri hanno notato, 2 e 4 è un AND bit a bit, quindi restituirà 0.

È possibile copiare quanto segue in test.html o qualcosa del genere e testare:

<html>
<body>
<script>
    alert("\"Cat\" && \"Dog\" = " + ("Cat" && "Dog") + "\n"
        + "2 && 4 = " + (2 && 4) + "\n"
        + "2 & 4 = " + (2 & 4));
</script>

3

Nella programmazione digitale del computer, un'operazione bit a bit opera su uno o più schemi di bit o numeri binari a livello dei loro singoli bit. È un'azione rapida e primitiva direttamente supportata dal processore e viene utilizzata per manipolare i valori per confronti e calcoli.

operazioni :

  • bit a bit AND

  • bit a bit OR

  • NON bit a bit

  • XOR bit a bit

  • eccetera

Voce di elenco

    AND|0 1        OR|0 1 
    ---+----      ---+---- 
      0|0 0         0|0 1 
      1|0 1         1|1 1 

   XOR|0 1        NOT|0 1 
   ---+----       ---+--- 
     0|0 1           |1 0 
     1|1 0

Per esempio.

    203: 1100 1011
AND  15: 0000 1111
------------------
  =  11: 0000 1011

Usi dell'operatore bit per bit

  • Gli operatori di spostamento a sinistra e spostamento a destra sono equivalenti alla moltiplicazione e alla divisione per x * 2 y rispettivamente.

Per esempio.

int main()
{
     int x = 19;
     printf ("x << 1 = %d\n" , x <<1);
     printf ("x >> 1 = %d\n", x >>1);
     return 0;
}
// Output: 38 9
  • L'operatore & può essere utilizzato per verificare rapidamente se un numero è pari o dispari

Per esempio.

int main()
{
    int x = 19;
    (x & 1)? printf("Odd"): printf("Even");
    return 0;
 }
// Output: Odd
  • Ricerca rapida minimo di xey senza if elseistruzione

Per esempio.

int min(int x, int y)
{
    return y ^ ((x ^ y) & - (x < y))
}
  • Conversione da decimale a binario

Per esempio.

#include <stdio.h>
int main ()
{
    int n , c , k ;
    printf("Enter an integer in decimal number system\n " ) ;
    scanf( "%d" , & n );
    printf("%d in binary number
    system is: \n " , n ) ;
    for ( c = 31; c >= 0 ; c -- )
    {
         k = n >> c ;
         if ( k & 1 )
              printf("1" ) ;
         else
              printf("0" ) ;
      }
      printf(" \n " );
      return 0 ;
}
  • La crittografia del gate XOR è una tecnica popolare, a causa della sua complessità e reale utilizzo da parte del programmatore.
  • l'operatore XOR bit a bit è l'operatore più utile dal punto di vista dell'intervista tecnica.

lo spostamento bit a bit funziona solo con il numero + ve

Inoltre esiste una vasta gamma di usi della logica bit a bit


"complixblity e reare ..."?
Jonathan Cross,

The left-shift and right-shift operators are equivalent to multiplication and division by x * 2y respectively.Giusto! muyiy.cn/question/program/102.html
xgqfrms

la mia soluzione repl.it/@xgqfrms/…
xgqfrms il

1

Potrebbe essere utile pensarlo in questo modo. Ecco come funziona AND (&):

Praticamente dice che sono entrambi questi numeri uno, quindi se hai due numeri 5 e 3 verranno convertiti in binari e il computer penserà

         5: 00000101
         3: 00000011

sono entrambi uno: 00000001 0 è falso, 1 è vero

Quindi l'AND di 5 e 3 è uno. L'operatore OR (|) fa la stessa cosa, tranne uno solo dei numeri deve essere uno sull'uscita 1, non entrambi.


-5

Continuavo a sentire quanto fossero lenti gli operatori bit per bit di JavaScript. Ho fatto alcuni test per il mio ultimo post sul blog e ho scoperto che erano diversi dal 40 all'80% in più rispetto all'alternativa aritmetica in diversi test. Forse erano lenti. Nei browser moderni, li adoro.

Ho un caso nel mio codice che sarà più veloce e più facile da leggere per questo. Terrò gli occhi aperti per altro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.