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 a
para a esquerda. Durante esta operação, os bits de ordem inferior adicionados à direita são zeros.
Exemplos:
Exemplo | Resultado |
---|---|
|
|
|
|
|
|
|
|
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 a
para a direita.
Exemplos:
Exemplo | Resultado |
---|---|
|
|
|
|
|
|
|
|
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 !
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 int
s e, na verdade, significam . Ou seja, o bit mais à esquerda é zero.0b11111111
0b00000000000000000000000011111111
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 a
para 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 ( true
ou false
). Um single long
é como um boolean
array 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 0b00001010
e 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, 1
exceto para o bit que você deseja redefinir.
Por exemplo, suponha que você tenha o número 0b00001010
e 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 1
exceto aquele que queremos que seja zero, primeiro deslocamos 1 b posições para a esquerda e, em seguida, usamos o NOT
operador 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 1
no 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 XOR
operaçã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 XOR
operador é 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));
}
}
GO TO FULL VERSION