Considere este código:
x = 1 # 0001
x << 2 # Shift left 2 bits: 0100
# Result: 4
x | 2 # Bitwise OR: 0011
# Result: 3
x & 1 # Bitwise AND: 0001
# Result: 1
Eu posso entender os operadores aritméticos em Python (e outras linguagens), mas nunca entendi os operadores 'bit a bit' muito bem. No exemplo acima (de um livro sobre Python), eu entendo o deslocamento para a esquerda, mas não os outros dois.
Além disso, para que os operadores bit a bit são realmente usados? Eu gostaria de alguns exemplos.
Respostas:
Operadores bit a bit são operadores que trabalham em valores de vários bits, mas conceitualmente um bit por vez.
AND
é 1 apenas se ambas as entradas forem 1, caso contrário, é 0.OR
é 1 se uma ou ambas as entradas forem 1, caso contrário, é 0.XOR
é 1 apenas se exatamente uma de suas entradas for 1, caso contrário, é 0.NOT
é 1 apenas se sua entrada for 0, caso contrário, é 0.Muitas vezes, eles podem ser melhor mostrados como tabelas de verdade. As possibilidades de entrada estão no topo e à esquerda, o bit resultante é um dos quatro (dois no caso de NOT, pois tem apenas uma entrada) valores mostrados na interseção das entradas.
Um exemplo é se você quiser apenas os 4 bits inferiores de um inteiro, faça o AND com 15 (binário 1111) para:
Nesse caso, os bits zero em 15 atuam efetivamente como um filtro, forçando os bits no resultado a também serem zero.
Além disso,
>>
e<<
muitas vezes são incluídos como operadores bit a bit, e eles "deslocam" um valor respectivamente para a direita e para a esquerda por um certo número de bits, jogando fora os bits que rolam da extremidade para a qual você está mudando, e alimentando bits zero no outro final.Então, por exemplo:
Observe que o deslocamento para a esquerda no Python é incomum, pois não usa uma largura fixa onde os bits são descartados - enquanto muitas linguagens usam uma largura fixa com base no tipo de dados, o Python simplesmente expande a largura para fornecer bits extras. Para obter o comportamento de descarte no Python, você pode seguir um deslocamento para a esquerda com um bit a bit
and
, como em um valor de 8 bits deslocando quatro bits para a esquerda:Com isso em mente, outro exemplo de operadores bit a bit é se você tiver dois valores de 4 bits que deseja compactar em um de 8 bits, poderá usar todos os três operadores (
left-shift
,and
eor
):& 15
operação garantirá que ambos os valores tenham apenas os 4 bits inferiores.<< 4
é um deslocamento de 4-bits para a esquerda para se moverval1
para a parte superior 4 bits de um valor de 8 bits.|
simplesmente combina esses dois juntos.Se
val1
é 7 eval2
é 4:fonte
Um uso típico:
|
é usado para definir um certo bit para 1&
é usado para testar ou limpar um certo bitDefina um bit (onde n é o número do bit e 0 é o bit menos significativo):
unsigned char a |= (1 << n);
Limpe um pouco:
unsigned char b &= ~(1 << n);
Alternar um pouco:
unsigned char c ^= (1 << n);
Teste um pouco:
unsigned char e = d & (1 << n);
Veja o caso da sua lista, por exemplo:
x | 2
é usado para definir o bit 1 dex
1x & 1
é usado para testar se o bit 0x
é 1 ou 0fonte
Um dos usos mais comuns de operações bit a bit é para analisar cores hexadecimais.
Por exemplo, aqui está uma função Python que aceita uma string como
#FF09BE
e retorna uma tupla de seus valores de vermelho, verde e azul.Eu sei que existem maneiras mais eficientes de se conseguir isso, mas acredito que este é um exemplo realmente conciso que ilustra as operações booleanas de mudança e bit a bit.
fonte
Acho que a segunda parte da pergunta:
Foi abordado apenas parcialmente. Esses são meus dois centavos nesse assunto.
As operações bit a bit em linguagens de programação desempenham um papel fundamental ao lidar com muitos aplicativos. Quase toda a computação de baixo nível deve ser feita usando esse tipo de operação.
Em todos os aplicativos que precisam enviar dados entre dois nós, como:
redes de computadores;
aplicações de telecomunicações (telefones celulares, comunicações por satélite, etc).
Na camada de comunicação de nível inferior, os dados geralmente são enviados no que chamamos de quadros . Os frames são apenas strings de bytes enviados por meio de um canal físico. Esses quadros geralmente contêm os dados reais mais alguns outros campos (codificados em bytes) que fazem parte do que é chamado de cabeçalho . O cabeçalho geralmente contém bytes que codificam algumas informações relacionadas ao status da comunicação (por exemplo, com sinalizadores (bits)), contadores de quadros, códigos de correção e detecção de erros, etc. Para obter os dados transmitidos em um quadro e construir o quadros para enviar dados, você precisará de operações bit a bit certas.
Em geral, ao lidar com esse tipo de aplicativo, uma API está disponível para que você não precise lidar com todos esses detalhes. Por exemplo, todas as linguagens de programação modernas fornecem bibliotecas para conexões de soquete, portanto, você não precisa realmente construir os quadros de comunicação TCP / IP. Mas pense nas boas pessoas que programaram essas APIs para você, elas tiveram que lidar com a construção de quadros com certeza; usando todos os tipos de operações bit a bit para ir e voltar da comunicação de nível inferior para a de nível superior.
Como um exemplo concreto, imagine que alguém lhe dê um arquivo que contém dados brutos que foram capturados diretamente pelo hardware de telecomunicações. Neste caso, para encontrar os quadros, você precisará ler os bytes brutos do arquivo e tentar encontrar algum tipo de palavra de sincronização, escaneando os dados bit a bit. Depois de identificar as palavras de sincronização, você precisará obter os quadros reais e SHIFT- los se necessário (e isso é apenas o início da história) para obter os dados reais que estão sendo transmitidos.
Outra família de aplicativos de baixo nível muito diferente é quando você precisa controlar o hardware usando algumas portas (tipo antigas), como portas paralelas e seriais. Essas portas são controladas configurando alguns bytes, e cada bit desses bytes tem um significado específico, em termos de instruções, para aquela porta (ver por exemplo http://en.wikipedia.org/wiki/Parallel_port ). Se você quiser construir um software que faça algo com esse hardware, você precisará de operações bit a bit para traduzir as instruções que deseja executar para os bytes que a porta entende.
Por exemplo, se você tiver alguns botões físicos conectados à porta paralela para controlar algum outro dispositivo, esta é uma linha de código que você pode encontrar no aplicativo soft:
Espero que isso contribua.
fonte
Espero que isso esclareça esses dois:
fonte
x & 1
não ilustra o efeito tão bem como ox & 2
faria.Pense em 0 como falso e 1 como verdadeiro. Então, bit a bit e (&) e ou (|) funcionam exatamente como regular e e ou, exceto que eles fazem todos os bits no valor de uma vez. Normalmente, você os verá usados para sinalizadores se tiver 30 opções que podem ser definidas (digamos, como estilos de desenho em uma janela), você não deseja ter que passar 30 valores booleanos separados para definir ou remover cada um, então use | para combinar opções em um único valor e, em seguida, usar & para verificar se cada opção está definida. Este estilo de passagem de sinalizador é muito usado pelo OpenGL. Uma vez que cada bit é um sinalizador separado, você obtém valores de sinalizador em potências de dois (também conhecidos como números que têm apenas um conjunto de bits) 1 (2 ^ 0) 2 (2 ^ 1) 4 (2 ^ 2) 8 (2 ^ 3) o a potência de dois informa qual bit está definido se o sinalizador estiver ativado.
Observe também que 2 = 10, portanto, x | 2 é 110 (6) e não 111 (7) Se nenhum dos bits se sobrepuser (o que é verdadeiro neste caso) | atua como adição.
fonte
Não vi isso mencionado acima, mas você também verá que algumas pessoas usam deslocamento para a esquerda e para a direita para operações aritméticas. Um deslocamento para a esquerda por x é equivalente a multiplicar por 2 ^ x (desde que não transborde) e um deslocamento para a direita é equivalente a dividir por 2 ^ x.
Recentemente, vi pessoas usando x << 1 e x >> 1 para dobrar e dividir pela metade, embora não tenha certeza se elas estão apenas tentando ser inteligentes ou se realmente há uma vantagem distinta sobre os operadores normais.
fonte
Jogos
Os conjuntos podem ser combinados usando operações matemáticas.
|
combina dois conjuntos para formar um novo contendo itens em ambos.&
obtém itens apenas em ambos.-
obtém itens no primeiro conjunto, mas não no segundo.^
obtém itens em qualquer um dos conjuntos, mas não em ambos.Tente você mesmo:
Resultado:
fonte
Este exemplo mostrará as operações para todos os quatro valores de 2 bits:
Aqui está um exemplo de uso:
fonte
Outro caso de uso comum é a manipulação / teste de permissões de arquivo. Consulte o módulo de estatísticas do Python: http://docs.python.org/library/stat.html .
Por exemplo, para comparar as permissões de um arquivo com um conjunto de permissões desejado, você pode fazer algo como:
Eu elenco os resultados como booleanos, porque eu só me importo com a verdade ou a falsidade, mas seria um exercício válido imprimir os valores bin () para cada um.
fonte
not bool((mode ^ desired_mode) & 0777)
. Ou (mais fácil de entender):not (mode & 0777) ^ desired_mode == 0
. E deixará apenas os bits interessantes, o XOR verificará que todos os bits desejados estão configurados. A== 0
comparação explícita é mais significativa do quebool()
.setWindowFlags
. Exemplo:setWindowFlags(SplashScreen | WindowStaysOnTopHint)
. Ainda acho isso confuso, pois parece que você está definindo um botão de alternância para 'ligado', então parece mais intuitivo 'e' nesse caso.As representações de bits de inteiros são freqüentemente usadas na computação científica para representar matrizes de informações verdadeiro-falsas porque uma operação bit a bit é muito mais rápida do que iterar por meio de uma matriz de booleanos. (Linguagens de nível superior podem usar a ideia de uma matriz de bits.)
Um bom e simples exemplo disso é a solução geral para o jogo Nim. Dê uma olhada no código Python na página da Wikipedia . Faz uso intenso de bit a bit exclusivo ou
^
,.fonte
Pode haver uma maneira melhor de descobrir onde um elemento da matriz está entre dois valores, mas, como mostra este exemplo, o & funciona aqui, enquanto e não funciona.
fonte
Não vi isso ser mencionado. Este exemplo mostrará a operação decimal (-) para valores de 2 bits: AB (somente se A contiver B)
esta operação é necessária quando mantemos um verbo em nosso programa que representa bits. às vezes precisamos adicionar bits (como acima) e às vezes precisamos remover bits (se o verbo contiver então)
com python: 7 & ~ 4 = 3 (remova de 7 os bits que representam 4)
com python: 1 & ~ 4 = 1 (remova de 1 os bits que representam 4 - neste caso, 1 não é 'contém' 4) ..
fonte
Embora a manipulação de bits de um inteiro seja útil, muitas vezes para protocolos de rede, que podem ser especificados até o bit, pode-se exigir a manipulação de sequências de bytes mais longas (que não são facilmente convertidas em um inteiro). Neste caso, é útil empregar a biblioteca bitstring que permite operações bit a bit nos dados - por exemplo, pode-se importar a string 'ABCDEFGHIJKLMNOPQ' como uma string ou como hex e bit shift-lo (ou realizar outras operações bit a bit):
fonte
os seguintes operadores bit a bit: & , | , ^ e ~ retornam valores (com base em suas entradas) da mesma forma que as portas lógicas afetam os sinais. Você pode usá-los para emular circuitos.
fonte
Para inverter os bits (ou seja, complemento / inversão de 1), você pode fazer o seguinte:
Como o valor ExORed com todos os resultados 1s em inversão, para uma determinada largura de bit, você pode usar ExOR para invertê-los.
fonte