[SP-pm] Operadores Bit-a-Bit (Bitwise)

breno breno at rio.pm.org
Mon May 31 00:08:31 PDT 2010


2010/5/31 "Flávio R. Lopes" <flavio.lopes em links.inf.br>:
> Boa noite pessoal.
> Ainda seguindo nos meus estudos, me deparei com um capítulo que trata dos
> "Bitwise Operators".
> Achei "meio complicado" !!!
>
> Parecem-se muito com os comparadores lógicos
>
> Enfim, ONDE isto é usado ou PARA QUE isto é usado?
>

Resposta curta: se vc realmente não tem idéia do que é ou pra que é
usado, vc não precisa disso. Pule e seja feliz :-)

É sério. Algumas linguagens de programação são minimalistas e voltadas
para um tipo de problema específico. Perl 5 é uma linguagem complexa e
de uso geral, o que significa que foi especialmente projetada para
resolver uma série de problemas. Pense em Perl como uma lingua. Você
sabe português, não sabe? O que é um "camote"? Ou um "extrário"?
"Oligolécito"? Não sabe? Pois é, nem eu. E não precisei nem procurar
muito: abri o dicionário aqui em 3 páginas aleatórias e elas estavam
lá. Quando vi pensei "aaahhhhnnnn ok", e agora que estou escrevendo,
já fiz questão de esquecê-las novamente. Não fazem parte do meu
vocabulário pq não preciso delas. O dia que surgirem, peço licença,
olho o "pai dos burros" e sigo em frente. Perl (e outras linguagens
verborrágicas) são assim também. Um dia você olha um código chamando
uma função que não conhece, e perldoc nela. Ou, se um dia tiver um
problema qualquer, uma busca simples por palavras chaves (ou em listas
como essas) te apontará para esse tipo de conhecimento e
funções/módulos associados. Então, não perca tempo tentando saber
tudo. Com tanta informação no mundo, precisamos escolher sabiamente
com o que ocupar a mente ;-)

Resposta longa: Como vc achou "meio complicado", vou começar a
resposta do ONDE e PRA QUE com "O QUE". Operadores "bitwise", às vezes
traduzidos como "bit-a-bit", servem pra fazer operações com bits.
Enquanto operadores lógicos avaliam cada lado da operação apenas como
verdadeiro ou falso, operações bit-a-bit geram um valor numérico entre
os dois lados da operação.

Em computadores, seus dados são armazenados em grandes coleções de
zeros e uns, os bits. Números decimais, por exemplo, são representados
em forma binária (base 2, números compostos apenas por bits):

0 =>         0
1 =>         1
2 =>       10
3 =>       11
4 =>     100
5 =>     101
6 =>     110
7 =>     111
8 =>   1000
9 =>   1001
10 => 1010
11 => 1011
12 => 1100
13 => 1101
14 => 1110
15 => 1111

e assim por diante.

As operações desse tipo são feitas bit-a-bit. Vejamos como exemplo a
operação "E" (AND), que é 1 apenas se os dois bits avaliados forem 1,
e 0 caso contrário. Assim, ao fazermos "3 & 14", estamos calculando na
verdade "0011 & 1110" (veja tabela acima). Isso fará uma comparação
(da esquerda pra direita) de 0 com 1 (resultando em 0), depois de 0
com 1 novamente (0), depois de 1 com 1 (resultando em 1) e finalmente,
de 1 com 0 (0). O valor final, portanto, será "0010", ou seja, "2" (na
base decimal):

   0 0 1 1
& 1 1 1 0
--------------
   0 0 1 0

As operações mais comuns entre dois valores são E (AND), OU (OR), e OU
EXCLUSIVO (XOR), que podem ser representados pelas seguintes
tabelas-verdade (observe cada linha para combinações de bits em $p e
$q, e para o bit resultante da operação entre eles):

      E (AND)
--------------------------
$p ,  $q ,  $p & $q
  0 ,    0 ,      0
  0 ,    1 ,      0
  1 ,    0 ,      0
  1 ,    1 ,      1


      OU (OR)
--------------------------
$p ,  $q ,  $p | $q
  0 ,    0 ,      0
  0 ,    1 ,      1
  1 ,    0 ,      1
  1 ,    1 ,      1


OU EXCLUSIVO (XOR)
--------------------------
$p ,  $q ,  $p ^ $q
  0 ,    0 ,      0
  0 ,    1 ,      1
  1 ,    0 ,      1
  1 ,    1 ,      0


Há ainda o NÃO (NOT), que inverte todos os bits do elemento:

$p   ~$p
 0     1
 1     0


Agora, de volta à sua pergunta original:

Operações bit a bit são muito utilizadas na manipulação de dados
binários (imagens, criptografia, etc) e quando espaço é um problema
(como alguns sistemas embutidos ou operações em massa). Dois exemplos
pra vc:

1) Máscaras de rede são números de 32 bits usados pra separar a parte
correspondente à rede pública, à subrede e aos hosts. Quando dizemos
que uma subrede tem máscara 255.255.255.0, estamos fazendo uma
operação binária AND entre esse valor
(11111111.11111111.11111111.00000000) e o valor da rede, também em
binário.

2) Quando temos valores que podem ser apenas verdadeiro ou falso
(também chamados de flags), podemos otimizar o espaço ocupado
atribuindo um bit para cada flag. Por exemplo:

POSSUI_FOO = 0001
POSSUI_BAR = 0010
POSSUI_BAZ  = 0100
POSSUI_MEH = 1000

Assim, não nos importamos com o valor decimal resultante mas sim com
quais flags estão ativas. O valor 1001, por exemplo, possui apenas as
flags "FOO" e "MEH" ativas. Note que, conforme nossa representação
binário-decimal, cada bit ativo pode ser representado por uma potência
de 2:

0001 == 1 == 2**0
0010 == 2 == 2**1
0100 == 4 == 2**2
1000 == 8 == 2**3

etc.

Uma rápida olhada em nossas tabelas verdade e vemos que podemos
atribuir flags através de OR:

my $flags = 0;
my ($IS_FOO, $IS_BAR, $IS_BAZ, $IS_MEH) = (1, 2, 4, 8);

$flags = $flags | $IS_FOO;  # ativa a flag 'FOO'
$flags = $flags | $IS_BAZ;   # ativa a flag 'BAZ'

e testar cada flag através de um AND:

# flag 'FOO' está ativa?
if ( $flags & $IS_FOO ) {
  ...
}

Pacotes IPv4 e outras estruturas de dados que precisam de otimização
de espaço usam isso, já que dessa forma não precisam reservar um (ou
mais) bytes para cada flag.

Esse tipo de cenário pode ser encontrado até fora de ambientes
computacionais, como uma prova de concurso com N afirmativas valendo
1, 2, 4, 8, 16, 32 e que pede ao aluno pra dizer a soma das
afirmativas corretas (OR).


É isso. Mas não se acostume, esse é o tipo de pergunta cuja resposta
pode ser facilmente encontrada aqui:

http://tinyurl.com/2aggysf


[]s

-b


More information about the SaoPaulo-pm mailing list