O que são operadores bit a bit?

129

Eu sou alguém que escreve código apenas por diversão e que realmente não se aprofundou nele em ambientes acadêmicos ou profissionais; portanto, coisas como esses operadores bit a bit realmente me escapam.

Eu estava lendo um artigo sobre JavaScript, que aparentemente suporta operações bit a bit. Continuo vendo essa operação mencionada em alguns lugares e tentei ler para descobrir exatamente o que é, mas simplesmente não entendi nada. Então, o que são eles? Exemplos claros seriam ótimos! : D

Apenas mais algumas perguntas - quais são algumas aplicações práticas de operações bit a bit? Quando você pode usá-los?

clique
fonte
2
Para mais perguntas, você pode adicionar uma nova pergunta SO e referenciar esta. Você provavelmente obterá um conjunto melhor de respostas dessa maneira.
Greg Hewgill 10/11/2008

Respostas:

186

Como ninguém abordou o assunto de por que eles são úteis:

Uso muito operações bit a bit ao trabalhar com sinalizadores. Por exemplo, se você quiser passar uma série de sinalizadores para uma operação (por exemplo File.Open(), com o modo de Leitura e o modo de Gravação ambos ativados), poderá transmiti-los como um valor único. Isso é feito atribuindo a cada sinalizador possível seu próprio bit em um conjunto de bits (byte, short, int ou long). Por exemplo:

 Read: 00000001
Write: 00000010

Portanto, se você deseja passar para ler e escrever, você passaria (READ | WRITE) que combina os dois em

00000011

Que então pode ser descriptografado na outra extremidade, como:

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

que verifica

00000011 &
00000001

que retorna

00000001

que não é 0, portanto, o sinalizador especifica READ.

Você pode usar o XOR para alternar vários bits. Eu usei isso ao usar um sinalizador para especificar entradas direcionais (Cima, Baixo, Esquerda, Direita). Por exemplo, se um sprite está se movendo horizontalmente, e eu quero que ele gire:

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

Simplesmente XOR o valor atual com (ESQUERDA | DIREITA) que desativará ESQUERDA e DIREITA, neste caso.

A troca de bits é útil em vários casos.

x << y

é o mesmo que

x * 2 anos

se você precisar multiplicar rapidamente por uma potência de dois, mas esteja atento para mudar um bit para o bit superior - isso torna o número negativo, a menos que não seja assinado. Também é útil ao lidar com diferentes tamanhos de dados. Por exemplo, lendo um número inteiro de quatro bytes:

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

Supondo que A seja o byte mais significativo e D seja o menos. Terminaria como:

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

As cores geralmente são armazenadas dessa maneira (com o byte mais significativo ignorado ou usado como Alpha):

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

Para encontrar os valores novamente, basta mudar os bits para a direita até que estejam na parte inferior e depois mascarar os bits restantes de ordem superior:

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

0xFFé o mesmo que 11111111. Então, essencialmente, para Red, você faria o seguinte:

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
fonte
x << n, então n deve estar na forma de 2 ^ valor?
Ahmed C
28

Vale a pena notar que as tabelas verdadeiras de um bit listadas como outras respostas funcionam apenas em um ou dois bits de entrada por vez. O que acontece quando você usa números inteiros, como:

int x = 5 & 6;

A resposta está na expansão binária de cada entrada:

  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

Cada par de bits em cada coluna é executado através da função "AND" para fornecer o bit de saída correspondente na linha inferior. Portanto, a resposta para a expressão acima é 4. A CPU realizou (neste exemplo) 8 operações "AND" separadas em paralelo, uma para cada coluna.

Menciono isso porque ainda me lembro de ter esse "AHA!" momento em que aprendi sobre isso há muitos anos.

Greg Hewgill
fonte
Uau, isso faz muito mais sentido agora. Parecia muito mais complicado do que aparentemente é. Obrigado. Não sei ao certo qual escolher como a resposta certa, pois há muitas boas, e não posso votar novamente .. obrigado
clique
27

Operadores bit a bit são operadores que trabalham um pouco de cada vez.

AND é 1 apenas se as duas entradas forem 1.

OR é 1 se uma ou mais de suas entradas forem 1.

XOR é 1 apenas se exatamente uma de suas entradas for 1.

NOT é 1 somente se sua entrada for 0.

Estes podem ser melhor descritos como tabelas de verdade. As possibilidades de entradas estão na parte superior e esquerda, o bit resultante é um dos quatro valores (dois no caso de NOT, pois possui apenas uma entrada) mostrados na interseção das duas entradas.

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

Um exemplo é se você deseja apenas os 4 bits inferiores de um número inteiro, E AND com 15 (binário 1111), para:

    203: 1100 1011
AND  15: 0000 1111
------------------
 IS  11: 0000 1011
paxdiablo
fonte
16

Estes são os operadores bit a bit, todos suportados em JavaScript:

  • op1 & op2- O ANDoperador compara dois bits e gera um resultado de 1 se os dois bits forem 1; caso contrário, ele retornará 0.

  • op1 | op2- O ORoperador compara dois bits e gera um resultado de 1 se os bits forem complementares; caso contrário, ele retornará 0.

  • op1 ^ op2- O EXCLUSIVE-ORoperador compara dois bits e retorna 1 se um dos bits for 1 e fornece 0 se os dois bits forem 0 ou 1.

  • ~op1- O COMPLEMENToperador é usado para inverter todos os bits do operando.

  • op1 << op2- O SHIFT LEFToperador move os bits para a esquerda, descarta o bit da extrema esquerda e atribui ao bit mais à direita o valor 0. Cada movimento para a esquerda multiplica efetivamente op1 por 2.

  • op1 >> op2- O SHIFT RIGHToperador move os bits para a direita, descarta o bit da extrema direita e atribui ao bit mais à esquerda o valor 0. Cada movimento para a direita divide efetivamente o op1 pela metade. O bit de sinal mais à esquerda é preservado.

  • op1 >>> op2- O operador SHIFT RIGHT- ZERO FILLmove os bits para a direita, descarta o bit da extrema direita e atribui ao bit mais à esquerda o valor 0. Cada movimento para a direita divide efetivamente op1 pela metade. O bit de sinal mais à esquerda é descartado.

Jeff Hillman
fonte
"se os bits são complementares" - o que?
Andrey Tyukin
@AndreyTyukin dois bits são complementares, se um deles é um eo outro é 0.
Jeff Hillman
@JeffHillman De acordo com sua descrição no comentário, 1 e 1 não são "complementares". Então, não está claro para mim por que 1 | 11e não 0, e como |é que então deve ser diferente ^. Eu tive que usar essa pergunta / pergunta como alvo duplicado há alguns dias e desejei que, após 10 anos, houvesse uma duplicata canônica mais clara para esse tipo de perguntas.
Andrey Tyukin 29/05/19
4

Para resumir um pouco mais, isso tem muito a ver com a representação binária do valor em questão.

Por exemplo (em decimal):
x = 8
y = 1

sairia para (em binário):
x = 1000
y = 0001

A partir daí, você pode executar operações computacionais como 'e' ou 'ou'; nesse caso:
x y =
1000 
0001
------
1001

ou ... 9 em decimal

Espero que isto ajude.

javamonkey79
fonte
|é uma operação OR?
Si8
Por alguma razão, isso fazia mais sentido para mim. Ainda não tenho certeza sobre a x | y = 1000 0001 |parte
samayo 17/03/17
4

Quando o termo "bit a bit" é mencionado, algumas vezes é esclarecido que esse não é um operador "lógico".

Por exemplo, em JavaScript, os operadores bit a bit tratam seus operandos como uma sequência de 32 bits (zeros e uns) ; enquanto isso, operadores lógicos são normalmente usados ​​com valores booleanos (lógicos), mas podem funcionar com tipos não-booleanos.

Veja expr1 && expr2, por exemplo.

Retorna expr1 se puder ser convertido em false; caso contrário, retorna expr2. Portanto, quando usado com valores booleanos, && retorna true se os dois operandos forem verdadeiros; caso contrário, retorna false.

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

Como outros observaram, 2 e 4 são AND bit a bit, portanto retornará 0.

Você pode copiar o seguinte para test.html ou algo assim e testar:

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

Na programação de computadores digitais, uma operação bit a bit opera em um ou mais padrões de bits ou números binários no nível de seus bits individuais. É uma ação rápida e primitiva diretamente suportada pelo processador e é usada para manipular valores para comparações e cálculos.

operações :

  • AND bit a bit

  • OR bit a bit

  • NÃO bit a bit

  • XOR bit a bit

  • etc

Item da lista

    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

Por exemplo.

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

Usos do operador bit a bit

  • Os operadores de turno esquerdo e de turno direito são equivalentes à multiplicação e divisão por x * 2 y, respectivamente.

Por exemplo.

int main()
{
     int x = 19;
     printf ("x << 1 = %d\n" , x <<1);
     printf ("x >> 1 = %d\n", x >>1);
     return 0;
}
// Output: 38 9
  • O operador & pode ser usado para verificar rapidamente se um número é ímpar ou par

Por exemplo.

int main()
{
    int x = 19;
    (x & 1)? printf("Odd"): printf("Even");
    return 0;
 }
// Output: Odd
  • Localização rápida do mínimo de xey sem if elseinstrução

Por exemplo.

int min(int x, int y)
{
    return y ^ ((x ^ y) & - (x < y))
}
  • Conversão decimal em binária

Por exemplo.

#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 ;
}
  • A criptografia de porta XOR é uma técnica popular, devido à sua compatibilidade e facilidade de uso pelo programador.
  • O operador XOR bit a bit é o operador mais útil do ponto de vista da entrevista técnica.

a mudança bit a bit funciona apenas com o número + ve

Também existe uma ampla variedade de uso da lógica bit a bit

Prashant
fonte
"complixblity e reare ..."?
Jonathan Cross
The left-shift and right-shift operators are equivalent to multiplication and division by x * 2y respectively.Está certo! muyiy.cn/question/program/102.html
xgqfrms
minha solução repl.it/@xgqfrms/…
xgqfrms 15/08/19
1

Pode ajudar a pensar dessa maneira. É assim que AND (&) funciona:

Basicamente, diz que são esses dois números, então, se você tiver dois números 5 e 3, eles serão convertidos em binários e o computador pensará

         5: 00000101
         3: 00000011

são ambos um: 00000001 0 é falso, 1 é verdadeiro

Portanto, o AND de 5 e 3 é um. O operador OR (|) faz a mesma coisa, exceto que apenas um dos números deve ser um para gerar 1, não os dois.

user3677963
fonte
-5

Fiquei ouvindo sobre como os operadores de bits em JavaScript eram lentos. Fiz alguns testes para o meu último post no blog e descobri que eles eram 40% a 80% mais rápidos que a alternativa aritmética em vários testes. Talvez eles costumavam ser lentos. Nos navegadores modernos, eu os amo.

Eu tenho um caso no meu código que será mais rápido e fácil de ler por causa disso. Vou manter meus olhos abertos para mais.

Nosredna
fonte