Operações binárias

Bruno Soares
Labs
Published in
7 min readMay 26, 2009

--

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 Matriz de Leds, 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, entre outras linguagens.

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 |
|-----------------------|
| 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)
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:
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)
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:
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).

// DEC: 3439543
// BIN: 1101000111101110110111
var color:uint = 0x347BB7;

var r:uint = (color >> 16) & 0xFF;
var g:uint = (color >> 8) & 0xFF;
var b:uint = color & 0xFF;

trace(“Red:”, r, “Green:”, g, “Blue:”, b);
// Red: 52 Green: 123 Blue: 183
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:
var r:uint = 52;
var g:uint = 123;
var b:uint = 183;
var color:uint = (r << 16) | (g << 8) | b;

trace(color.toString(16));
// 347bb7

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.
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++):

// 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

--

--