Co to są operatory bitowe?

132

Jestem kimś, kto pisze kod tylko dla przyjemności i tak naprawdę nie zagłębiał się w niego ani w środowisku akademickim, ani zawodowym, więc takie rzeczy jak te operatory bitowe naprawdę mi umykają.

Czytałem artykuł o JavaScript, który najwyraźniej obsługuje operacje bitowe. Wciąż widzę tę operację wspomnianą w niektórych miejscach i próbowałem czytać, aby dowiedzieć się, co to dokładnie jest, ale po prostu wydaje mi się, że w ogóle jej nie rozumiem. Więc czym one są? Jasne przykłady byłyby świetne! :RE

Jeszcze tylko kilka pytań - jakie są praktyczne zastosowania operacji bitowych? Kiedy możesz ich użyć?

Kliknij
źródło
2
W przypadku dalszych pytań możesz dodać nowe pytanie SO i odwołać się do tego. W ten sposób prawdopodobnie uzyskasz lepszy zestaw odpowiedzi.
Greg Hewgill

Odpowiedzi:

187

Ponieważ nikt nie poruszył tematu, dlaczego są one przydatne:

Często używam operacji bitowych podczas pracy z flagami. Na przykład, jeśli chcesz przekazać serię flag do operacji (powiedzmy File.Open(), z włączonymi trybami odczytu i zapisu), możesz przekazać je jako jedną wartość. Osiąga się to poprzez przypisanie każdej możliwej flagi jej własnego bitu w zestawie bitów (bajt, krótki, int lub długi). Na przykład:

 Read: 00000001
Write: 00000010

Więc jeśli chcesz przekazać odczyt I zapis, powinieneś przekazać (CZYTAJ | ZAPISZ), który następnie łączy te dwa elementy w

00000011

Które następnie można odszyfrować na drugim końcu, na przykład:

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

który sprawdza

00000011 &
00000001

który powraca

00000001

która nie jest 0, więc flaga określa READ.

Możesz użyć XOR do przełączania różnych bitów. Użyłem tego, gdy używam flagi do określania kierunkowych wejść (w górę, w dół, w lewo, w prawo). Na przykład, jeśli duszek porusza się poziomo i chcę, aby się obracał:

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

Po prostu XOR aktualną wartość za pomocą (LEFT | RIGHT), co w tym przypadku wyłącza LEWO i włączam PRAWO.

Przesuwanie bitu jest przydatne w kilku przypadkach.

x << y

jest taki sam jak

x * 2 y

jeśli potrzebujesz szybko pomnożyć przez potęgę dwóch, ale uważaj na przesunięcie 1-bitowego bitu do górnego bitu - powoduje to, że liczba jest ujemna, chyba że jest bez znaku. Jest to również przydatne w przypadku różnych rozmiarów danych. Na przykład odczyt liczby całkowitej z czterech bajtów:

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

Zakładając, że A jest najbardziej znaczącym bajtem, a D najmniej. Skończyło się tak:

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

Kolory są często przechowywane w ten sposób (najbardziej znaczący bajt jest ignorowany lub używany jako alfa):

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

Aby ponownie znaleźć wartości, po prostu przesuń bity w prawo, aż znajdą się na dole, a następnie zamaskuj pozostałe bity wyższego rzędu:

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

0xFFjest taki sam jak 11111111. Zasadniczo w przypadku Reda zrobiłbyś to:

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)
Ed Marty
źródło
x << n, więc n musi mieć postać wartości 2 ^?
Ahmed C
28

Warto zauważyć, że jednobitowe tablice prawdy wymienione jako inne odpowiedzi działają tylko na jednym lub dwóch bitach wejściowych naraz. Co się dzieje, gdy używasz liczb całkowitych, takich jak:

int x = 5 & 6;

Odpowiedź leży w binarnym rozwinięciu każdego wejścia:

  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

Każda para bitów w każdej kolumnie jest przepuszczana przez funkcję „AND” w celu uzyskania odpowiedniego bitu wyjściowego w dolnej linii. Zatem odpowiedź na powyższe wyrażenie to 4. CPU wykonał (w tym przykładzie) 8 oddzielnych operacji „AND” równolegle, po jednej dla każdej kolumny.

Wspominam o tym, ponieważ wciąż pamiętam to „AHA!” moment, w którym dowiedziałem się o tym wiele lat temu.

Greg Hewgill
źródło
Wow, to ma teraz dużo więcej sensu. Brzmiało to o wiele bardziej skomplikowanie, niż się wydaje. Dzięki. Nie jestem pewien, którą wybrać jako właściwą odpowiedź, ponieważ jest mnóstwo dobrych i nie mogę tak głosować ... dzięki
kliknij
28

Operatory bitowe to operatory, które działają po kawałku na raz.

AND wynosi 1 tylko wtedy, gdy oba jego wejścia mają wartość 1.

LUB wynosi 1, jeśli jedno lub więcej jego wejść ma wartość 1.

XOR ma wartość 1 tylko wtedy, gdy dokładnie jedno z jego wejść ma wartość 1.

NIE jest 1 tylko wtedy, gdy jego wejście ma wartość 0.

Można je najlepiej opisać jako tablice prawdy. Możliwości wejść znajdują się na górze i po lewej stronie, wynikowy bit jest jedną z czterech (dwóch w przypadku NIE, ponieważ ma tylko jedno wejście) wartości pokazanych na przecięciu dwóch wejść.

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

Jednym z przykładów jest to, że jeśli chcesz tylko 4 dolne bity liczby całkowitej, to ORAZ to z 15 (binarne 1111), więc:

    203: 1100 1011
AND  15: 0000 1111
------------------
 IS  11: 0000 1011
paxdiablo
źródło
16

Oto operatory bitowe, wszystkie obsługiwane w JavaScript:

  • op1 & op2- ANDOperator porównuje dwa bity i generuje wynik 1, jeśli oba bity mają wartość 1; w przeciwnym razie zwraca 0.

  • op1 | op2- OROperator porównuje dwa bity i generuje wynik 1, jeśli bity są komplementarne; w przeciwnym razie zwraca 0.

  • op1 ^ op2- EXCLUSIVE-OROperator porównuje dwa bity i zwraca 1, jeśli jeden z bitów ma wartość 1, i daje 0, jeśli oba bity mają wartość 0 lub 1.

  • ~op1- COMPLEMENTOperator jest używany do odwracania wszystkich bitów operandu.

  • op1 << op2- SHIFT LEFTOperator przesuwa bity w lewo, odrzuca skrajny lewy bit i przypisuje skrajnemu prawemu bitowi wartość 0. Każdy ruch w lewo skutecznie mnoży op1 przez 2.

  • op1 >> op2- SHIFT RIGHTOperator przesuwa bity w prawo, odrzuca skrajny prawy bit i przypisuje skrajnemu lewemu bitowi wartość 0. Każdy ruch w prawo efektywnie dzieli op1 na pół. Zachowany jest skrajny lewy bit znaku.

  • op1 >>> op2- Operator SHIFT RIGHT- ZERO FILLprzesuwa bity w prawo, odrzuca skrajny prawy bit i przypisuje skrajnemu lewemu bitowi wartość 0. Każdy ruch w prawo skutecznie dzieli op1 na pół. Najbardziej lewy bit znaku jest odrzucany.

Jeff Hillman
źródło
„jeśli bity są komplementarne” - co?
Andrey Tyukin
@AndreyTyukin dwa bity są komplementarne, jeśli jeden z nich to 1, a drugi 0.
Jeff Hillman
@JeffHillman Zgodnie z opisem w komentarzu, 1 i 1 nie są „komplementarne”. Wtedy nie jest dla mnie jasne, dlaczego 1 | 1daje, 1a czego nie 0, i |czym ma się wtedy różnić ^. Kilka dni temu musiałem użyć tego pytania / odpowiedzi jako zduplikowanego celu i chciałem, aby po 10 latach można było uzyskać jaśniejszy kanoniczny duplikat tego rodzaju pytań.
Andrey Tyukin
4

Mówiąc bardziej szczegółowo, ma to wiele wspólnego z binarną reprezentacją danej wartości.

Na przykład (dziesiętnie):
x = 8
y = 1

wyjdzie do (binarnie):
x = 1000
y = 0001

Stamtąd możesz wykonywać operacje obliczeniowe, takie jak „and” lub „or”; w tym przypadku:
x | y =
1000 
0001 |
------
1001

lub ... 9 dziesiętnie

Mam nadzieję że to pomoże.

javamonkey79
źródło
|to operacja OR?
Si8
Z jakiegoś powodu miało to dla mnie największy sens. Nadal nie wiesz o x | y = 1000 0001 |część chociaż
samayo
4

Kiedy pojawia się termin „bitowy”, czasami wyjaśnia się, że nie jest to operator „logiczny”.

Na przykład w JavaScript operatory bitowe traktują swoje operandy jako ciąg 32 bitów (zer i jedynek) ; w międzyczasie operatory logiczne są zwykle używane z wartościami boolowskimi (logicznymi), ale mogą działać z typami innymi niż boolowskie.

Weźmy na przykład wyr1 i& wyr2.

Zwraca wyrażenie1, jeśli można je przekonwertować na fałsz; w przeciwnym razie zwraca wyrażenie2. Zatem, gdy jest używany z wartościami logicznymi, && zwraca prawdę, jeśli oba operandy są prawdziwe; w przeciwnym razie zwraca false.

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

Jak zauważyli inni, 2 & 4 jest bitowym AND, więc zwróci 0.

Możesz skopiować następujący plik do test.html lub coś podobnego i przetestować:

<html>
<body>
<script>
    alert("\"Cat\" && \"Dog\" = " + ("Cat" && "Dog") + "\n"
        + "2 && 4 = " + (2 && 4) + "\n"
        + "2 & 4 = " + (2 & 4));
</script>
Eugene Yokota
źródło
3

W cyfrowym programowaniu komputerowym operacja bitowa działa na jednym lub większej liczbie wzorów bitowych lub liczb binarnych na poziomie ich poszczególnych bitów. Jest to szybka, prymitywna akcja bezpośrednio obsługiwana przez procesor i służy do manipulowania wartościami do porównań i obliczeń.

operacje :

  • bitowe AND

  • bitowe OR

  • bitowe NIE

  • bitowe XOR

  • itp

Element listy

    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

Na przykład.

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

Zastosowania operatora bitowego

  • Operatory przesunięcia w lewo i przesunięcia w prawo są równoważne odpowiednio mnożeniu i dzieleniu przez x * 2 y .

Na przykład.

int main()
{
     int x = 19;
     printf ("x << 1 = %d\n" , x <<1);
     printf ("x >> 1 = %d\n", x >>1);
     return 0;
}
// Output: 38 9
  • Operator & może służyć do szybkiego sprawdzenia, czy liczba jest nieparzysta czy parzysta

Na przykład.

int main()
{
    int x = 19;
    (x & 1)? printf("Odd"): printf("Even");
    return 0;
 }
// Output: Odd
  • Szybkie wyszukiwanie minimum x i y bez if elseinstrukcji

Na przykład.

int min(int x, int y)
{
    return y ^ ((x ^ y) & - (x < y))
}
  • Zamiana liczb dziesiętnych na dwójkowe

Na przykład.

#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 ;
}
  • Szyfrowanie bramek XOR jest popularną techniką ze względu na jej kompletność i ponowne wykorzystanie przez programistę.
  • bitowy operator XOR jest operatorem najbardziej użytecznym z punktu widzenia wywiadu technicznego.

przesunięcie bitowe działa tylko z liczbą + ve

Istnieje również szeroki zakres zastosowań logiki bitowej

Prashant
źródło
„kompleksowość i hodowla…”?
Jonathan Cross
The left-shift and right-shift operators are equivalent to multiplication and division by x * 2y respectively.Zgadza się! muyiy.cn/question/program/102.html
xgqfrms
moje rozwiązanie repl.it/@xgqfrms/…
xgqfrms
1

Pomyśl o tym w ten sposób. Oto jak działa AND (&):

Zasadniczo mówi, że są to obie te liczby, więc jeśli masz dwie liczby 5 i 3, zostaną one zamienione na binarne i komputer pomyśli

         5: 00000101
         3: 00000011

są jednością: 00000001 0 to fałsz, 1 to prawda

Więc AND z 5 i 3 to jeden. Operator OR (|) robi to samo, z wyjątkiem tego, że tylko jedna z liczb musi być jeden, aby wyświetlić 1, a nie obie.

user3677963
źródło
-5

Ciągle słyszałem o tym, jak powolne były operatory bitowe JavaScript. Zrobiłem kilka testów do mojego ostatniego wpisu na blogu i odkryłem, że były od 40% do 80% szybsze niż alternatywa arytmetyczna w kilku testach. Być może kiedyś były powolne. W nowoczesnych przeglądarkach uwielbiam je.

Mam w kodzie jeden przypadek, który dzięki temu będzie szybszy i łatwiejszy do odczytania. Będę miał oczy otwarte na więcej.

Nosredna
źródło