Esmiuçando operadores bit-a-bit - Parte 1


Autor/fonte: Alisson Carlos de F. Rodrigues
E-mail/Url: http://www.phpbrasil.com/articles/article.php/id/1392
Tags: [ bit-a-bit ]



Digg del.icio.us

Os operadores bit-a-bit têm sido muito pouco utilizados por programadores PHP, contrastando com outras linguagens, onde são largamente utilizados. Tento por esse meu primeiro artigo, explicar como funciona e mostrar exemplos práticos do seu uso.

Provavelmente poucos aqui devem ter ouvido falar sobre operadores bit a bit, e dos que ouviram falar, poucos os conhecem a fundo e sabem trabalhar com eles. Então vou tentar explicar de uma forma simples e prática como essa “coisa” funciona.

Pois bem, primeiramente, tem esse nome “operadores bit a bit”, pois lidam literalmente com cada bit separadamente, aquele monte de 0 e 1 que são as linguagens de máquina.

Pra tentar explicar meio assim por cima, imagine que tenhamos 4 setinhas (direita, esquerda, cima, baixo), supomos que estamos dentro de um jogo. E ao pressionar qualquer uma dessas teclas é produzido um determinado número (números diferentes para cada uma). Podemos fazer o seguinte esquema: direita (1), esquerda (2), cima (4), baixo (8). Depois explico o porquê desses números.

Ok, então temos 4 ações, que é pressionar cada uma dessas teclas. Mas obviamente, em um jogo você não vai andar apenas em 4 direções, portanto podemos ter combinações dessas teclas, e pra cada uma dessas combinações, podemos adotar novos números. direita+cima (5), esquerda+cima (6), direita+baixo (9), esquerda+baixo (10). Ainda podemos ter outras combinações, com 3 teclas ou em um caso 4, mas não tratarei disso.

Você provavelmente deve estar se perguntando: “Tio Alissooooooooon, mas por que esses números? Por que você não usou 3 e 7?”. Calma meu querido, já vou explicar.

Você deve saber que tudo em uma computador é transformado em binário, aquelas infinitas combinações de 0 e 1. Vamos então transformar esses números acima em binários:

01: 1
02: 10
04: 100
05: 101
06: 110
08: 1000
09: 1001
10: 1010

Reparem naqueles primeiros números, das teclas individuais: 1, 10, 100, 1000. Se você pensou “são potências de 10” você acertou. Mas por que isso? Simplesmente porque eles possuem apenas um número “1” e com posições diferentes entre eles, pra visualizar melhor, observe:

0001
0010
0100
1000

Se o querido amigo é inteligente, já deve ter percebido que para cada uma das teclas, apenas um bit fica responsável, CHARAM. Simples assim, se a tecla está pressionada, o tal bit tem o número “1”, caso contrário tem o número “0”. Portanto, da direita pra esquerda, o primeiro bit é a tecla direita, o segundo a esquerda, o terceiro pra cima e o quarto...baixo. Quando pressionamos duas teclas, simplesmente aparece dois números “1”. Por exemplo, esquerda (10) + cima (100) = 110 = 6. Gostou? Pois é, se quiser testar os outros números (se usar windows), abra a calculadora do windows e coloque no modo cientifico, aperte o radio button “Bin” e digite o número binário e depois pressione o radio button “Dec”. Irá aparecer o número em decimal.

Agora supondo que pressionemos as teclas direita+esquerda+cima, o que aconteceria? Isso mesmo, formaria o número 111, que é...? 7, lembra dele amigo? E se pressionarmos esquerda+direita? Isso, 3. Entende agora porque não os usamos? Pois é, infelizmente você não pode andar para a direita e para a esquerda ao mesmo tempo.

Então, como podemos saber se determinada tecla foi ou não pressionada? Não, nada de substr, nem coisas horríveis como:

if ($numeroRetornado==1 || $numeroRetornado==5 || $numeroRetornado==9) {...

Deixa de ser preguiçoso, vamos usar Operadores bit-a-bit. Apresento-lhe eles agora (tirado do manual):

$a & $b - Os bits que estão ativos tanto em $a como $b são ativados;
$a | $b - Os bits que estão ativos em $a ou em $b são ativados;
$a ^ $b - Os bits que estão ativos em $a ou em $b, mas não em ambos, são ativados;
~ $a - Os bits que estão ativos em $a não são ativados, e vice-versa.

Em nosso caso usaremos o “&”, que serve, como dito acima, para ativar apenas o que estiver nas duas variáveis dadas. De uma forma mais simples, a posição que tiver o número 1 nas duas variáveis serão ativados, caso contrário será “0” o resultado. Por exemplo, você tem dois números:

%01.jpg%

Repare na ligação que existe entre os dois números, no caso do “&”, onde tiver dois números “1” será colocado “1”, caso contrário será colocado “0”.

Agora, vamos analisar nosso primeiro sistema. Nós queremos saber se a tecla da direita está pressionada, para isso, faremos a comparação do número retornado (101=5) com o número dessa tecla, que no caso é “1” (em binário é 1 mesmo):

%02.jpg%

No resultado temos o número da tecla pressionada. Pronto, podemos fazer isso com as outras teclas também, basta você pegar o valor retornado e comparar com o valor padrão de cada tecla, se chegar a esse mesmo resultado é porque tal tecla foi pressionada.

Agora você me pergunta: como fazer isso em PHP? Simples, nesse último caso você faria:

$direita = 1 & 5;

Simples não? Pois é, $direita vai conter o valor 1. Naquele primeiro caso, dos valores 236 e 125, se você fizesse:

$direita = 236 & 125;

$direita conteria o valor 108. Então para verificar se foi pressionada a tal tecla, basta fazer:

if ($numeroRetornado & $numeroDaTecla == $numeroDaTecla)
print “Está pressionada”;
else print “Não está pressionada”;

Deixo a oportunidade pra vocês fazerem os testes sozinhos.

O operador “&”, portanto, serve para retornar o número 1 quando presente nos dois números dados.

O operador “|” serve para retornar o número 1 quando este estiver presente em qualquer um dos dois números dados.

O operador “^” serve para retornar o número 1 quando este estiver presente em apenas um dos dois números dados.

O operador “~” serve para inverter os valores dados, ou seja, onde for 1 será retornar 0 e onde for 0 será retornado 1.

Além desses quatro operadores, ainda existe mais dois, que trato separadamente por funcionar de uma forma um pouco diferente. Neste caso não é feito comparação entre os dois elementos dados, temos (tirado do manual):

$a << $b - Desloca os bits de $a $b passos para a esquerda;
$a >> $b - Desloca os bits de $a $b passos para a direita.

Você deve estar se perguntando: “Pra que diabos eu vou usar essa coisa?”. Pois bem, vou tentar passar um exemplo prático, que está contido num script para transformar imagens coloridas em PB que eu postei no laboratório de scripts a pouco tempo.

A função imagecolorat() busca a cor de um determinado pixel numa imagem, e retorna um valor inteiro, mas não queremos este valor assim, portanto precisamos transforma-lo em binário para depois retornar o RGB.

Transformando este valor retornado em binário, vamos obter um número com 24 dígitos, cada 8 dígitos é uma das 3 cores RGB. Então, os 8 primeiros são Red, os 8 do meio Green, e os 8 últimos Blue. Nem preciso dizer que 8 números binários representam 1 byte, preciso? Pois é. Daí você pensa: “Obaaaaaaaaaaaaa, vou usar substr pra pegar essa informação”. Vai uma pinóia. Pelo amor de Deus, deixa de ser folgado e aprende a mecher com a bagaça, substr denovo não, definitivamente.

Imagine que a funçãozinha ali retornou esse número:

111000000000000000000000

Legal, você quer pegar os 8 primeiros números, simples (nada de substr), você vai deslocar esses 8 números para a direita, tirando os 16 que estão do seu lado direito, portanto estes SOMEM, assim (14680064 é esse número grandão ali em cima em decimal):

$r = 14680064 >> 16;

Pronto, retorna 11100000 ou 224 em decimal.

Agora você quer pegar os 8 números do meio. Deve pegar novamente o número grandão e deslocar 8 números para a direita:

$g = (14680064 >> 8) & 0xFF;

Repare que dessa vez eu usei aquele operador bit-a-bit apresentado lá no começo, vamos analisar: você puxou os 16 primeiros números para direita, ou seja, excluiu os 8 últimos (o 8 do código ali), e está comparando com o valor 255 (FF em hexadecimal ou 11111111 em decimal), o operador “&” só vai ativar o que tiver nos dois números dados, portanto, no script abaixo, é excluído os 8 primeiros números (antes já havia sido excluído os 8 últimos).

1110000000000000
0000000011111111

Em lugar algum temos dois números “1”, portanto aqui vai ser retornado “0” simplesmente.

Só falta o blue, aqui nem precisamos deslocar bit algum, basta compararmos com 255:

$b = 14680064 & 0xFF;

Analisando:

111000000000000000000000
000000000000000011111111

Repare que novamente você não tem dois números “1” em lugar algum. Portanto, será retornado novamente 0. Então deu pra perceber que essa comparação com o número 255 serve somente pra excluir os primeiros dígitos, nos 8 últimos ele não altera nada.

Finalmente descobrimos o RGB, que é 224,0 e 0. Pra ficar mais fácil podemos transformar em hexadecimal, que é a maneira mais utilizada (não em PHP, a função imagecolorallocate por exemplo usa a primeira maneira como argumentos e transforma em um inteiro), usando a função dechex() do próprio PHP, assim obteríamos E0,0 e 0 ou simplesmente “E00000”.

Finalmente, chegamos ao fim desse gigante tutorial, espero que tenha ficado muito bem explicado e sirva para vocês não sofrerem tanto pra aprender quanto eu, já que não consegui encontrar nenhum material explicado assim, tive que ir na raça.




Enviado por xKuRt em 26/12/2006 às 16:47


Itens relacionados

Esmiuçando operadores bit-a-bit - Parte 2

Avaliação

Esta publicação ainda não foi avaliada!


Avaliar:


A avaliação de publicações é restrita a membros cadastrados e logados no nosso site.



Comentários

Este artigo ainda não foi comentado ou o(s) comentário(s) que foi(ram) enviado(s) a ele ainda não foi(ram) publicado(s).


Envio de comentário:




  

Terça, 25 de Abril de 2017




Top 5 membros

Últimos membros online

Últimos membros cadastrados



Capa do livro
ASP.NET MVC em Ação


Capa do livro
Criando Aplicações PHP com Zend e Dojo: Padrões e Reuso com Frameworks - Edição Revisada e Ampliada


Capa do livro
Objetos, Abstração, Estrutura de Dados e Projetos Usando Java





Hostnet

IMD