Operações binárias
Ultimamente tenho me deparado com muitos trechos de códigos que utilizam operações binárias, como chaveamento de multiplexador, extração de RGB a partir de um inteiro ou hexadecimal, bitshift para controlar LED Matrix, etc… E finalmente dei aquela estuda, agora vai ai um post sobre o que resultou o estudo.
Obs.: Os trechos de códigos deste post foram escritos em ActionScript, mas pode ser aplicado a C, C++, Java, Processing, PHP, entre outras linguagens.
• Introdução
• Bit Shift
• Operador >> (bitwise right shift)
• Operador << (bitwise left shift)
• Operações Bitwise
• Operador & (bitwise AND)
• Operador | (bitwise OR)
• Operador ^ (bitwise XOR)
• Operador ~ (bitwise NOT)
• Exemplos
• Extraindo o RGB de uma cor
• Chaveando multiplexador 4051
Introdução
Um operador binário, como o nome sugere, é um operador que trabalha com a representação binária do número, e como normalmente não sabemos a representação binária dos números de cabeça, vamos utilizar a tabela abaixo:
----------------------- | BIN | DEC | HEX | |-----------------------| | 1 | 1 | 1 | | 10 | 2 | 2 | | 11 | 3 | 3 | | 100 | 4 | 4 | | 101 | 5 | 5 | | 110 | 6 | 6 | | 111 | 7 | 7 | | 1000 | 8 | 8 | | 1001 | 9 | 9 | | 1010 | 10 | A | | 1011 | 11 | B | | 1100 | 12 | C | | 1101 | 13 | D | | 1110 | 14 | E | | 1111 | 15 | F | | 10000 | 16 | 10 | | 10001 | 17 | 11 | | 10010 | 18 | 12 | | 10011 | 19 | 13 | | 10100 | 20 | 14 | |-----------------------| | 11111111 | 255 | FF | -----------------------
A tabela lista os números de 1 à 20 e 255 em três bases diferentes:
• Binário (BIN)
• Decimal (DEC)
• Hexadecimal (HEX)
Analisando a tabela podemos concluir que 3d = 11b, 19d = 10011b (as letras d e b significam decimal e binário respectivamente). Lembrando que pode ser utilizada uma calculadora que opere em binário (como a do windows) ou uma alternativa de conversão de bases on-line como está: “Conversão de número binário”.
Então vamos deslocar, escorregar, escovar alguns bits para entender melhor.
Operador >>
Deslocamento de bits para a direita (bitwise right shift)
1 2 3 4 | trace(8 >> 1); // 4 trace(8 >> 2); // 2 trace(8 >> 3); // 1 trace(8 >> 4); // 0 |
Olhando os números na base decimal faz pouco sentido, ou talvez nenhum sentido, então passamos os números corretos para a base binária e tudo fica mais claro:
8d = 1000b (8 decimal é igual a 1000 em binário), então:
1000b >> 1 (deslocando uma casa para direita) temos o número:
100b que em decimal é 4(dê uma olhada na tabela).
Agora ficou fácil não? Vamos deslocar o número 13:
1 | trace(13 >> 1); // 6 |
13 em binário é 1101, deslocando uma casa para a direita (ou removendo 1 bit), fica 110, e 110 é igual a 6 em decimal.
Operador <<
Deslocamento de bits para a esquerda (bitwise left shift)
1 2 3 | trace(2 << 1); // 4 trace(2 << 2); // 8 trace(2 << 3); // 16 |
Agora é só seguir o mesmo raciocino já utilizando anteriormente.
Se 2 em base binária é igual a 10 e deslocarmos um bit para esquerda, vamos ganhar mais um zero, ficando com 100 que é igual a 4 em decimal.
Operador &
AND binário (bitwise AND)
O operador & compara bit a bit os números a sua direita e esquerda, por exemplo o resultado de 10 & 11 é 10:
1010 & 1011 ------ 1010
A comparação bit-a-bit somente retorna True (1) quando os bits comparados são iguais a 1, caso contrário retorna False (0). Formando assim um novo número.
Mais alguns exemplos para fortalecer:
|14 & 9|13 & 11|20 & 9|14 & 10|89 & 112|45 & 77|255 & 13|112 & 255| | | | | | | | | | | 1110 | 1101 | 10100| 1110 | 1011001| 101101| 11111111| 1110000| |& 1001 |& 1011 |& 1001|& 1010 |& 1110000|& 1001101|& 1101|& 11111111| | ---- | ---- | -----| ---- | -------| -------| --------| --------| | 1000 | 1001 | 0| 1010 | 1010000| 1101| 1101| 1110000| | 8d | 9d | 0d| 10d | 80d| 13d| 13d| 112d|
Operador |
OR binário (bitwise OR)
O operador | tem a mesma função do operador OR comum (||) só que atua bit-a-bit, assim como os outros operadores binários. Vejamos um exemplo:
1010 | 1011 ------ 1011
Se um dos bits comparados forem iguais a 1 a expressão retornará 1, caso os dois bits comparados forem iguais a 0, a expressão retorna 0. Agora vamos refazer o exemplo anterior trocando apenas o operador & (and binário) por | (or binário):
|14 | 9|13 | 11|20 | 9|14 | 10|89 | 112|45 | 77|255 | 13|112 | 255| | | | | | | | | | | 1110 | 1101 | 10100| 1110 | 1011001| 101101| 11111111| 1110000| || 1001 || 1011 || 1001|| 1010 || 1110000|| 1001101|| 1101|| 11111111| | ---- | ---- | -----| ---- | -------| -------| --------| --------| | 1111 | 1111 | 11101| 1110 | 1111001| 1101101| 11111111| 11111111| | 15d | 15d | 29d| 14d | 121d| 109d| 255d| 255d|
Operador ^
OU exclusivo (bitwise XOR)
A letra X na frente do OR significa Exclusive (Exclusive OR). Isso quer dizer que este operador faz a comparação binária de dois números e resulta os bits que são diferentes. Por exemplos, quais são os bits diferentes entre os números 10 e 11?
1010
^ 1011
------
1
Vamos novamente trocar o operador do exemplo anterior para analisar os resultados:
|14 ^ 9|13 ^ 11|20 ^ 9|14 ^ 10|89 ^ 112|45 ^ 77|255 ^ 13|112 ^ 255| | | | | | | | | | | 1110 | 1101 | 10100| 1110 | 1011001| 101101| 11111111| 1110000| |^ 1001 |^ 1011 |^ 1001|^ 1010 |^ 1110000|^ 1001101|^ 1101|^ 11111111| | ---- | ---- | -----| ---- | -------| -------| --------| --------| | 111 | 110 | 11101| 100 | 101001| 1100000| 11110010| 10001111| | 7d | 6d | 29d| 4d | 41d| 96d| 242d| 143d|
Operador ~
Negação (bitwise NOT)
O operador NOT inverte o sinal e complementa em um.
Negando o número 168 (~168) teremos -169.
Alguns exemplos:
1 2 3 4 5 6 | trace(~7); // -8 trace(~-7); // 6 trace(~14); // -15 trace(~13); // -14 trace(~255); // -256 trace(~112); // -113 |
Extraindo o RGB de uma cor
Sabendo que uma cor no formato RGB utiliza dois dígitos hexadecimais para definir quanto existe de Vermelho, Verde e Azul (respectivamente), formando cores como: Vermelho (FF0000), Cinza (C0C0C0), Laranja (FF9900), etc. Temos ai a possibilidade de gerar 16.581.375 de cores com este código, é só fazer a conta para conferir: 255 * 255 * 255 ou FF * FF * FF.
Vamos desmembrar um tom de azul (#347BB7) para saber quanto esta cor tem de Vermelho, Verde e Azul (o valor dos canais RGB).
1 2 3 4 5 6 7 8 9 10 |
Linha 5) Deslocando 16 bits para a direita temos:
1101000111101110110111 >> 16 = 110100 (DEC: 52)
Para o caso do vermelho não precisamos continuar a expressão (& 0xFF),
pois deslocando 16 bits para a direita já temos o resultado do vermelho,
mas se a cor estivesse no formato ARGB (Alpha Red Green Blue), seria necessário.
Linha 6) Deslocando 8 bits para conseguir o verde:
1101000111101110110111 >> 8 = 11010001111011 (DEC: 13435)
Só com o valor do deslocamentos não vamos conseguir a cor verde, então utilizamos o
operador & (AND) com o valor 255 (0xFF) para extrair a parte binária que nos interessa:
11010001111011 (DEC: 13435)
& 11111111 (DEC: 255, HEX: 0xFF)
--------------
01111011 (DEC: 123)
Linha 7) Para extrair o azul não precisamos deslocar bits e sim pegar os últimos 8 bits:
1101000111101110110111
& 11111111 (DEC: 255, HEX: 0xFF)
----------------------
10110111 (DEC: 183)
Agora voltando para o hexadecimal:
1 2 3 4 5 6 7 |
Linha 4) Deslocando 16 bits para a esquerda do número 52 (Vermelho):
110100 << 16 = 1101000000000000000000
Deslocando 8 bits para a esquerda do número 123 (Verde):
1111011 << 8 = 111101100000000
Efetuando o OR (|) com o resultado das duas operações ((r << 16) | (g << 8)):
1101000000000000000000 | 111101100000000 ---------------------- 1101000111101100000000
Efetuando a última operação, o OR com o Azul (183)
1101000111101100000000 | 0000000000000010110111 ---------------------- 1101000111101110110111
O resultado agora ficou claro. O número 1101000111101110110111 (binário) é igual a 3439543 (decimal) e 347BB7 (hexadecimal).
Chaveando multiplexador 4051
A tarefa de chavear um Multiplexador / Demultiplexador (MUX / DEMUX) 4051 é muito parecida com a extração dos canais RGB de uma cor. Você só precisa Ligar ou Desligar três pinos de seleção (select pins) para que o circuito interprete o valor gerado e transmita a voltagem da entrada desejada.
Existe um gif animado do RogerCom muito didático que demonstra o funcionamento do CI 4051, gif animado CI 4051 aqui.
Por exemplo, para ler a entrada 3, precisamos desligar o pino de seleção 0, ligar o 1 e o 2, formando assim o número 011 (binário) que é igual a 3 em decimal. Veja no código (Escrito em Arduino / C++):
1 2 3 4 5 6 7 8 9 10 11 12 | // Entrada desejada int count = 3; // Extração dos bits ativos byte s0 = count & 0x1; byte s1 = (count >> 1) & 0x1; byte s2 = (count >> 2) & 0x1; // Ligando ou desligando os pinos de seleção digitalWrite(2, s0); digitalWrite(3, s1); digitalWrite(4, s2); |
Conteúdo relacionado:
• Bitwise operation on Wikipedia
Posts relacionados:
Po brother, mandou suuuper bem no post cara….vc eh foda!!
Parabéns ae! Sucesso!
Valew Fabão, é nozes
Parabéns pelo post…. excelente.
Mas me diga uma coisa…. como ficaria a conversão de um RGBA pra hexadecimal? Vc tem idéia?
Abraço
Hilton Ferraz
Salve Hilton, Obrigado.
O código ARGB ou RGBA adiciona mais 8 casas binárias para comportar 255 (hex 0xFF) então você só precisa escorregar mais 8 casas, assim:
var a:uint = 0×37;
var r:uint = 0×34;
var g:uint = 0x7b;
var b:uint = 0xb7;
var color:uint = (a << 24) | (r << 16) | (g << 8) | b;
trace(color.toString(16));
// 37347bb7
Abraços
Ola Bruno, muinto bom seu blog, parabéns pela sua iniciativa de passar seus conhecimentos nesta area. Bem, eu venho aqui pra tirar uma curiosidade minha, vi na explicaçao de que vc deu em operaçoês binarias e gostaria de saber o que significa esta variavel ou comando – ( uint ). para que serve onde usar. Obrigado .
obs: agradeço se me responder por email .
Olá Ailton, o uint é um tipo de dados do ActionScript (Adobe Flash), é o mesmo tipo de dados que o “unsigned int” do C++.
Ou seja, é um tipo de dados que só aceita números inteiros maiores que 0.
Abraços e obrigado!
E ae, Bruno. Muito bom o post. Bem explicados as matemáticas doidas. =D
Abraço.