A che cosa servono le operazioni sui bit

Le operazioni bit a bit lavorano su ciascuna cifra binaria separatamente. AND lascia a 1 solo i bit che sono 1 in entrambi i numeri, OR quelli che sono 1 in almeno uno, XOR quelli che sono diversi, NOT li capovolge tutti. Sono le istruzioni più elementari di un processore, e le più veloci.

Si usano per leggere e impostare singoli flag in un intero, per applicare maschere come quelle di rete, per i permessi dei file Unix, per i colori codificati in un intero, per i checksum e la crittografia. Un AND con 0x0F tiene i quattro bit bassi, un OR con 0x80 accende il bit più alto.

Scorrere a sinistra di n posizioni moltiplica per 2^n, scorrere a destra divide. Con i numeri negativi conta la differenza fra scorrimento logico, che inserisce zeri, e aritmetico, che ricopia il bit di segno: -16 >> 2 fa -4, mentre lo scorrimento logico dà un numero positivo grande.

Errori frequenti

  • Dimenticare la larghezza della parola: NOT 0 fa 255 su 8 bit ma 4294967295 su 32.
  • Usare lo scorrimento logico su un numero con segno aspettandosi una divisione: per i negativi serve quello aritmetico.
  • In JavaScript usare & e | su numeri oltre i 32 bit: vengono troncati in silenzio. Per 64 bit servono i BigInt.

Domande frequenti

Che differenza c'è fra >> e >>>?

Entrambi scorrono a destra. >> è aritmetico e ricopia il bit di segno, quindi mantiene negativi i numeri negativi; >>> è logico e inserisce zeri, trattando il numero come senza segno.

A che cosa serve XOR?

A scambiare o confrontare bit: A XOR B dice quali bit differiscono, A XOR A fa 0 e A XOR B XOR B torna ad A. Per questo è alla base di checksum, parità e molti cifrari.

Come si controlla se un bit è acceso?

Con un AND fra il numero e una maschera che ha solo quel bit a 1: se il risultato è diverso da zero, il bit è acceso. Il bit k ha maschera 1 << k.

Come funziona questo calcolo

Ogni operazione agisce sui bit nella stessa posizione: AND = 1 se entrambi sono 1, OR = 1 se almeno uno è 1, XOR = 1 se sono diversi, NOT inverte. A << n = A · 2^n troncato alla larghezza w; A >>> n = ⌊A / 2^n⌋ senza segno; A >> n divide conservando il segno. La rotazione a sinistra di n è (A << n) OR (A >>> (w − n)). Il valore con segno è quello senza segno meno 2^w quando il bit più alto è 1.