Algebra com BITs

0
6663

Olá pessoal!

Nesse novo artigo usaremos matemática com BITS, operadores lógicos e outros conceitos interessantes para manipular números inteiros.


Os números e a matemática dominam nossa vida. Não passamos um dia sem usarmos uma álgebra ou um calculo mesmo que não seja diretamente. O que não nos mostram na escola é que os números podem ter diferentes representações e só nos é apresentada o sistema de base dez ou decimal.

No mundo das maquinas aonde os números são representados em conjuntos de 1 e 0 temos a base dois ou binária que será usada no dia a dia de um programador de sistemas embarcados.Bem como a hexadecimal aonde temos um sistema de base 16 que nos ajudara a representar números binários longos.

Os números no sistema binário serão representados com sequências de 1 e 0 porem como trabalhar esses valores?
Que numero decimal o binário 10010010 representa?

A conversão se dará assim:
casa: 7 6 5 4 3 2 1 0
numero: 1 0 0 1 0 0 1 0
2^Casa:128 64 32 16 8 4 2 1 = 128+16+2=146.

A conversão se trata basicamente de multiplicar o binário da referida casa por uma potencia de 2 elevado a casa do numero. O maior numero decimal a ser representado por um numero de 8Bits seria 255 então podemos usar em um registrador um inteiro de 0 a 255.

Seguindo essa linha de raciocínio qual seria o maior numero representando por um inteiro de 16 bits?


Operadores lógicos

Para quem nunca fez um curso voltado a área de tecnologia fica complicado entender a lógica por trás de varias ferramentas implementadas em compiladores.

Temos basicamente quatro operadores lógicos no C:

OR representado pelo “|”
AND representado pelo “&”
XOR representado pelo “^”
NOT representado pelo “~”

Cada operador possui uma tabela verdade que mostra o seu comportamento:

Bitwise OR (OU)(|):
0 | 0 == 0
0 | 1 == 1
1 | 0 == 1
1 | 1 == 1

Como observamos o comportamento desse operador se trata quando “uma entrada ou outra” estão em 1 a saída será um.

Exemplo usando 8bits: 0b10001000|0b0110001 =?

0b10001000
0b01100001 =0b11101001

A lógica OR servira para certificar que um certo bit em um numero será 1.


Bitwise AND (e)(&):
0 & 0 == 0
0 & 1 == 0
1 & 0 == 0
1 & 1 == 1

Como observamos o comportamento desse operador se trata quando “uma entrada e a outra” estão em 1 a saída será um.

Exemplo usando 8bits: 0b10001001&0b0110001 =?

0b10001001
&
0b01100001 = 0b00000001

A lógica AND servira para verificar qual o estado de um bit em certa casa decimal.
Por exemplo:

Ob11001100 & 0b00001000 == 1
ou
Ob11001100 & 0b00000001 == 0


Bitwise NOT (não)(~):
~ 0 == 1
~ 1 == 0

Como observamos o operador NOT inverte o valor de entrada.

Exemplo usando 8bits: ~0b10001001 == 0b01110110

A logica NOT poderá ser usada para inverter o estado de um numero ou mesmo mudar o comportamento de operadores lógicos anteriores como o OR ou AND.


Bitwise XOR (OU EXCLUSIVA)(^):
0 ^ 0 == 0
0 ^ 1 == 1
1 ^ 0 == 1
1 ^ 1 == 0

Verificamos que a saída do operador será “1” quando as entradas forem diferentes ou exclusivamente um ou outro

Exemplo usando 8bits: 0b10000001^0b00000001 =?

0b10000001
^
0b00000001 = 0b10000000

Pois:
casa 7: 1^0==1
casa 6: 0^0==0
casa 5: 0^0==0
casa 4: 0^0==0
casa 3: 0^0==0
casa 2: 0^0==0
casa 1: 0^0==0
casa 0: 1^0==0

A lógica XOR servira para inverter o estado de um determinado BIT por exemplo.


BIT SHIFT

Podemos alterar a posição de um bit usando os operadores de deslocamento.

>> : para deslocar a direita
<< : para deslocar a esquerda
exemplo:

0b00010000<<3==0b10000000
0b00010000>>7==0b00000001


Mas finalmente amigo para que serve tudo isso.

Irei dar exemplos simples:

Como veremos em um futuro artigo cada pino de GPIO corresponde a um BIT de um endereço de memoria. O PORTD seria o nome do endereço com os 8bits referentes aos 8 pinos do mesmo.

1: Queremos acionar uma luz no pino 4 do PORTD porem não podemos alterar nenhum outro BIT no mesmo PORT pois no pino 3 temos uma sirene e no 2 o controle de uma tranca.Destacando que o primeiro BIT é representado por 0 e o 8º sera o numero 7.

O estado atual do PORTD esta assim: 0b00000100

Como vimos o pino 2 é a tranca e esta acionada não posso em uma operação desativar essa tranca.

Se eu fizer somente isso PORTD=Ob00010000; teremos um erro catastrofico pois iremos limpar o BIT referente a tranca.

Para um correto acionamento usaremos a lógica OR: PORTD=PORTD|0b0001000

Como o estado do PORTD era: 0b00000100

0b00000100
|
0b00010000 == 0b00010100

Sucesso!!! Acionaremos nossa lampada sem desativar nossa tranca

Podemos simplificar a expressão ainda assim: PORTD|=0b0001000 ou ainda usando bit shift com a seguinte expressão PORTD|=(1<<4)

Passado algum tempo queremos que a luz seja desactivada porem como no caso anterior sem mexer nos outros BITS.

Não da para usar a lógica OR pois 1|0 ira retornar “1” não fazendo diferença. Usando uma lógica AND temos o resultado esperado pois 1&0==0 e para manter os outros BITS podemos fazer uma AND com 1 pois 1&1==1 e 0&1==0 então todo BIT que estiver em 1 continuara bem como 0 continuara 0.

0b00010100
&
0b11101111 = 0b00000100

então obtemos a expressão PORTD=PORTD&0b11101111; seguindo a mesma lógica da lógica OR podemos reduzir a expressão PORTD&=&0b11101111;.

Podemos usar o bitshift nesse caso porem com a seguinte lógica:

(1<<4)==0b00010000
~0b00010000==0b11101111

Realizaremos então um deslocamento a esquerda e apos uma inversão resultando na expressão:
PORTD&=~(1<<4);

ótimo agora podemos setar e apagar bits sem alterar outros em um endereço de memoria.

Pessoal por hoje é só.Ate a proxima!

LEAVE A REPLY