1. Spostamento a sinistra bit a bit

Java ha anche 3 operatori di spostamento bit per bit : se ne hai davvero bisogno, puoi semplicemente spostare tutti i bit di un numero di diverse posizioni a sinistra oa destra.

Per spostare i bit di un numero a sinistra, è necessario l' operatore bitwise shift a sinistra . Così è scritto:

a << b

Dove aè il numero i cui bit vengono spostati ed bè un numero che indica quante volte spostare i bit del numero aa sinistra. Durante questa operazione, i bit di ordine inferiore aggiunti a destra sono zeri.

Esempi:

Esempio Risultato
0b00000011 << 1
0b00000110
0b00000011 << 2
0b00001100
0b00000011 << 5
0b01100000
0b00000011 << 20
0b001100000000000000000000

Spostare una cifra a sinistra ha lo stesso effetto di moltiplicare un numero per 2.

Vuoi moltiplicare un numero per 16? 16 è uguale a 2 4 . Quindi sposti le cifre del numero 4 a sinistra


2. Spostamento bit per bit a destra

I bit possono anche essere spostati a destra. Per fare ciò, utilizzare l' operatore di spostamento a destra bit per bit . Così è scritto:

a >> b

Dove aè il numero i cui bit vengono spostati ed bè il numero di volte per spostare i bit del numero aa destra.

Esempi:

Esempio Risultato
0b11000011 >> 1
0b01100001
0b11000011 >> 2
0b00110000
0b11000011 >> 5
0b00000110
0b11000011 >> 20
0b00000000

Lo spostamento di una cifra a destra ha lo stesso effetto della divisione di un numero per 2.

Durante questa operazione, i bit più significativi aggiunti a sinistra sono zeri, ma non sempre !

Importante!

Il bit più a sinistra di un numero con segno è chiamato bit di segno : se il numero è positivo, lo è 0; ma se il numero è negativo, questo bit è 1.

Quando si spostano i bit di un numero a destra, normalmente si sposta anche il valore del bit di segno e il segno del numero va perso. Di conseguenza, per i numeri negativi (dove il bit più a sinistra è 1), questo bit riceve un trattamento speciale. Quando si spostano i bit di un numero a destra, 0viene aggiunto a a sinistra se il bit più a sinistra era 0, e a 1viene aggiunto a sinistra se il bit più a sinistra era 1.

Ma nell'esempio sopra, questo non sembra essere il risultato. Perché? Perché i letterali interi sono ints, e  in realtà significa . Cioè, il bit più a sinistra è zero.0b111111110b00000000000000000000000011111111

Molti programmatori sono frustrati da questo comportamento di spostamento a destra e preferirebbero che il numero fosse sempre riempito di zeri. Quindi Java ha aggiunto un altro operatore di spostamento a destra .

Così è scritto:

a >>> b

Dove a è il numero i cui bit vengono spostati ed b  è il numero di volte per spostare i bit del numero aa destra. Questo operatore aggiunge sempre zeri a sinistra, indipendentemente dal valore originale del bit di segno del numero a.



3. Lavorare con le bandiere

I programmatori hanno creato un campo di studio quasi completamente nuovo sulla base delle operazioni bit a bit e shift: lavorare con i flag.

Quando i computer avevano pochissima memoria, era molto popolare stipare molte informazioni in un unico numero. Un numero è stato trattato come un array di bit: un int è di 32 bit e un long è di 64 bit.

Puoi scrivere molte informazioni in un tale numero, specialmente se hai bisogno di memorizzare valori logici ( trueo false). Un singolo longè come un booleanarray composto da 64 elementi. Questi bit erano chiamati flag e venivano manipolati usando le seguenti operazioni:

  • impostare la bandiera
    (rendere un bit specifico uguale a 1)
  • reimposta bandiera
    (rendere un bit specifico uguale a 0)
  • bandiera di controllo
    (controlla il valore di un bit specifico)

Ed ecco come si fa con gli operatori bit a bit.

Mettere una bandiera

Per impostare un bit specifico su 1, è necessario eseguire un'operazione OR bit a bit tra il numero di cui si desidera impostare il bit e un numero appositamente creato, dove solo quel bit è 1.

Ad esempio, supponiamo di avere il numero 0b00001010e di dover impostare il quinto bit su 1. In tal caso, è necessario:

0b00001010 | 0b00010000 = 0b00011010

Se il quinto bit fosse già stato impostato su uno, non sarebbe cambiato nulla.

In generale, l'operazione di impostazione di un flag può essere scritta come segue

a | (1 << b)

Dove a è il numero il cui bit sarà impostato su 1. Ed b è la posizione del bit da impostare. L'uso dell'operatore di spostamento a sinistra è super conveniente qui, poiché puoi immediatamente capire con quale bit stiamo lavorando.

Reimpostare un flag

Per azzerare un bit specifico (cioè impostarlo a 0) senza disturbare gli altri bit, è necessario eseguire un'operazione &tra il numero di cui si desidera azzerare il bit (cioè impostarlo a 0) e un numero appositamente creato, dove tutti i bit sono uguali a 1tranne per il bit che vuoi reimpostare.

Ad esempio, supponiamo di avere il numero 0b00001010e di dover impostare il 4° bit su 0. In tal caso, è necessario:

0b00001010 & 0b11110111 = 0b00000010

Se il 4° bit fosse già stato impostato a zero, non sarebbe cambiato nulla.

In generale, l'operazione di azzeramento di un flag può essere scritta come segue

a & ~(1 << b)

Dove a è il numero il cui bit verrà reimpostato su 0. Ed b è la posizione del bit da cancellare.

Per ottenere un numero in cui tutti i bit sono 1tranne quello che vogliamo sia zero, spostiamo prima di 1 b  posizioni a sinistra, quindi utilizziamo l' NOToperatore bit a bit per invertire il risultato.

Controllo di una bandiera

Oltre ad impostare o resettare uno specifico flag, a volte basta verificare se un dato flag è impostato, cioè se un certo bit è uguale a 1. Questo è abbastanza facile da fare con un file &.

Ad esempio, supponiamo di dover verificare se il 4° bit è impostato su 1nel numero 0b00001010. Allora devi fare questo:

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

In generale, l'operazione di controllo di un flag può essere scritta come segue

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

Dove a è il numero il cui bit viene controllato. Ed b è la posizione della punta da controllare.


4. Crittografia

L' XORoperazione bit per bit viene spesso utilizzata dai programmatori per una semplice crittografia. In generale, tale crittografia è simile a questa:

result = number ^ password;

Dove number sono i dati che vogliamo crittografare, password è un numero speciale utilizzato come "password" per i dati ed result è il numero crittografato.

number == (number ^ password) ^ password;

La cosa importante qui è che quando l' XORoperatore viene applicato due volte a un numero, produce il numero originale, indipendentemente dalla "password".

Per recuperare number da encrypted result, è sufficiente eseguire nuovamente l'operazione:

original number = result ^ password;

Esempio:

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));
   }
}