1. Deslocamento à esquerda bit a bit

Java também tem 3 operadores de deslocamento bit a bit : Se você realmente precisar, pode simplesmente deslocar todos os bits de um número várias posições para a esquerda ou para a direita.

Para deslocar os bits de um número para a esquerda, você precisa do operador de deslocamento à esquerda bit a bit . Assim está escrito:

a << b

Onde aé o número cujos bits estão sendo deslocados, e bé um número que indica quantas vezes deslocar os bits do número apara a esquerda. Durante esta operação, os bits de ordem inferior adicionados à direita são zeros.

Exemplos:

Exemplo Resultado
0b00000011 << 1
0b00000110
0b00000011 << 2
0b00001100
0b00000011 << 5
0b01100000
0b00000011 << 20
0b001100000000000000000000

Deslocar um dígito para a esquerda tem o mesmo efeito que multiplicar um número por 2.

Quer multiplicar um número por 16? 16 é igual a 2 4 . Então você desloca o número 4 dígitos para a esquerda


2. Deslocamento bit a bit para a direita

Os bits também podem ser deslocados para a direita. Para fazer isso, use o operador de deslocamento à direita bit a bit . Assim está escrito:

a >> b

Onde aé o número cujos bits estão sendo deslocados e bé o número de vezes para deslocar os bits do número apara a direita.

Exemplos:

Exemplo Resultado
0b11000011 >> 1
0b01100001
0b11000011 >> 2
0b00110000
0b11000011 >> 5
0b00000110
0b11000011 >> 20
0b00000000

Deslocar um dígito para a direita tem o mesmo efeito que dividir um número por 2.

Durante esta operação, os bits de ordem superior adicionados à esquerda são zeros, mas nem sempre !

Importante!

O bit mais à esquerda de um número com sinal é chamado de bit de sinal : se o número for positivo, é 0; mas se o número for negativo, esse bit é 1.

Ao deslocar os bits de um número para a direita, o valor do bit de sinal normalmente também mudaria e o sinal do número seria perdido. Da mesma forma, para números negativos (onde o bit mais à esquerda é 1), esse bit recebe tratamento especial. Ao deslocar os bits de um número para a direita, a 0é adicionado à esquerda se o bit mais à esquerda for 0, e a 1é adicionado à esquerda se o bit mais à esquerda for 1.

Mas no exemplo acima, esse não parece ser o resultado. Por que? Porque os literais inteiros são ints e,  na verdade, significam . Ou seja, o bit mais à esquerda é zero.0b111111110b00000000000000000000000011111111

Muitos programadores ficam frustrados com esse comportamento de deslocamento à direita e preferem que o número seja sempre preenchido com zeros. Portanto, Java adicionou outro operador de deslocamento à direita .

Assim está escrito:

a >>> b

Onde a é o número cujos bits estão sendo deslocados e b  é o número de vezes para deslocar os bits do número apara a direita. Este operador sempre acrescenta zeros à esquerda, independentemente do valor original do bit de sinal do número a.



3. Trabalhando com sinalizadores

Os programadores criaram um campo de estudo quase totalmente novo com base em operações bit a bit e shift: trabalhando com sinalizadores.

Quando os computadores tinham muito pouca memória, era muito popular amontoar muitas informações em um único número. Um número foi tratado como uma matriz de bits: um int tem 32 bits e um long tem 64 bits.

Você pode escrever muitas informações em tal número, especialmente se precisar armazenar valores lógicos ( trueou false). Um single longé como um booleanarray composto por 64 elementos. Esses bits foram chamados de sinalizadores e foram manipulados usando as seguintes operações:

  • definir bandeira
    (faça um bit específico igual a 1)
  • redefinir bandeira
    (faça um bit específico igual a 0)
  • bandeira de verificação
    (verifique o valor de um bit específico)

E aqui está como isso é feito com operadores bit a bit.

Definindo uma bandeira

Para definir um bit específico como 1, você precisa executar uma operação OR bit a bit entre o número cujo bit deseja definir e um número especialmente criado, onde apenas esse bit é 1.

Por exemplo, suponha que você tenha o número 0b00001010e precise definir o 5º bit como 1. Nesse caso, você precisa:

0b00001010 | 0b00010000 = 0b00011010

Se o 5º bit já tivesse sido definido como um, nada teria mudado.

Em geral, a operação de definir um sinalizador pode ser escrita da seguinte forma

a | (1 << b)

Onde a é o número cujo bit será definido como 1. E b é a posição do bit a ser definido. Usar o operador shift esquerdo é super conveniente aqui, pois você pode saber imediatamente com qual bit estamos trabalhando.

Redefinindo uma bandeira

Para redefinir um bit específico (ou seja, configurá-lo para 0) sem perturbar outros bits, você precisa realizar uma &operação entre o número cujo bit você deseja redefinir (ou seja, definir para 0) e um número especialmente criado, onde todos os bits são iguais, 1exceto para o bit que você deseja redefinir.

Por exemplo, suponha que você tenha o número 0b00001010e precise definir o 4º bit como 0. Nesse caso, você precisa:

0b00001010 & 0b11110111 = 0b00000010

Se o 4º bit já tivesse sido definido como zero, nada teria mudado.

Em geral, a operação de reinicialização de um sinalizador pode ser escrita da seguinte forma

a & ~(1 << b)

Onde a é o número cujo bit será redefinido para 0. E b é a posição do bit a ser limpa.

Para obter um número onde todos os bits estão 1exceto aquele que queremos que seja zero, primeiro deslocamos 1 b  posições para a esquerda e, em seguida, usamos o NOToperador bit a bit para inverter o resultado.

Verificando uma bandeira

Além de definir ou redefinir um sinalizador específico, às vezes você só precisa verificar se um determinado sinalizador está definido, ou seja, se um determinado bit é igual a 1. Isso é muito fácil de fazer com um bit a bit &.

Por exemplo, suponha que você precise verificar se o 4º bit está definido como 1no número 0b00001010. Então você precisa fazer isso:

if ( (0b00001010 & 0b00001000) == 0b00001000 )

Em geral, a operação de verificação de um sinalizador pode ser escrita da seguinte forma

(a & (1 << b)) == (1 << b)

Onde a é o número cujo bit está sendo verificado. E b é a posição do bit a ser verificada.


4. Criptografia

A XORoperação bit a bit é freqüentemente usada por programadores para criptografia simples. Em geral, essa criptografia se parece com isso:

result = number ^ password;

Onde number estão os dados que queremos criptografar, password é um número especial usado como "senha" para os dados e result é o número criptografado.

number == (number ^ password) ^ password;

O importante aqui é que quando o XORoperador é aplicado a um número duas vezes, ele produz o número original, independentemente da "senha".

Para recuperar number do encrypted result, basta realizar a operação novamente:

original number = result ^ password;

Exemplo:

class Solution
{
   public static int[] encrypt(int[] data, int password)
   {
     int[] result = new int[data.length];
     for (int i = 0; i <  data.length; i++)
       result[i] = data[i] ^ password;
     return result;
   }

   public static void main(String[] args)
   {
     int[] data =  {1, 3, 5, 7, 9, 11};
     int password = 199;

     // Encrypt the array of data
     int[] encrypted = encrypt(data, password);
     System.out.println(Arrays.toString(encrypted));

     // Decrypt the array of data
     int[] decrypted = encrypt(encrypted, password);
     System.out.println(Arrays.toString(decrypted));
   }
}