"¡Hola, amigo!"

"También me gustaría hablar sobre máscaras de bits y XOR".

"Ya sabe que los números consisten en bits y puede realizar varias operaciones en estos bits. Una máscara de bits es una representación de varios valores lógicos diferentes (valores verdadero/falso) como un solo entero. En este caso, cada valor booleano corresponde a un bit específico. Así es como se podría hacer esto:"

"La representación binaria de potencias de dos (1, 2, 4, 8, 16, 32, ...) solo implica poner un bit:"

Número representación binaria
1 0000 0001
2 0000 0010
4 0000 0100
8 0000 1000
dieciséis 0001 0000
19 (no es una potencia de dos) 0001 0011
31 (no es una potencia de dos) 0001 1111

"Entonces, cualquier número entero puede tratarse como una matriz de bits o una matriz de valores booleanos".

"Así es como puede almacenar diferentes valores booleanos en un número:"

valores booleanos
boolean a = true;
boolean b = false;
boolean c = true;
boolean d = false;
Valores empaquetados en un número:
int result = 0;
 if (a) result += 1; // 1 == 20 — bit 0
 if (b) result += 2; // 2 == 21 — bit 1
 if (c) result += 4; // 4 == 22 — bit 2
 if (d) result += 8; // 8 == 23 — bit 3

"Ahora cada bit es 1 si la variable booleana correspondiente era verdadera".

En nuestro caso, las variables a y c eran verdaderas, por lo que el resultado es igual a 1+4 == 5

0000 0101
0000 dcba

"Creo que sé lo que está pasando".

"Bueno, si lo entiendes, sigamos adelante".

"Un int tiene 32 bits. Uno de ellos se usa para el signo del número y los otros 31 se pueden usar para almacenar los valores de 31 variables booleanas".

"Un largo tiene 64 bits donde podemos almacenar 63 variables booleanas".

"Sí."

"Docenas de variables metidas en un solo número. Son bastantes".

"Pero, ¿dónde se aplica esto?"

"Principalmente en situaciones en las que necesita almacenar mucha información sobre objetos. Cuando almacena mucha información sobre un objeto, siempre hay un par de docenas de variables booleanas. "Con este enfoque, todas están convenientemente almacenadas en un número ."

"Con énfasis en la palabra 'almacenado'. Porque en realidad usar el número no es tan conveniente".

"Por cierto, eso es justo lo que quería preguntar. ¿Cómo extraemos el valor booleano del número?"

"No es complicado en absoluto. Digamos que necesita determinar si el bit 6 está configurado en 1 (2 elevado a cinco es 32). Podríamos comprobarlo así:"

Combina números en uno:
int a = 32; // 25 == 0010 0000
int b = 8; // 23 == 0000 1000
int c = 2; // 21 == 0000 0010

int result = a + b + c; // 32 + 8 + 2 == 42 == 0010 1010
Extraiga valores comprobando bits específicos:
int a = result & 32; // 0010 1010 & 0010 0000 = 0010 0000
int b = result & 8; // 0010 1010 & 0000 1000 = 0000 1000
int c = result & 2; // 0010 1010 & 0000 0010 = 0000 0010

"Así, trabajar con máscaras de bits implica tres operaciones:"

1)  Establecer un bit específico a 0

2)  Establecer un bit específico a 1

3)  Verifique el valor del bit específico.

"Tome el bit 6, por ejemplo".

"¿Cómo configuras el bit 6 a 1?"

Código Descripción
result = result | 01000000;
result |= 01000000;
¿Cómo se configura el bit 6 a 1?
result = result & 10111111;
result &= 10111111;
¿Cómo se configura el bit 6 a 0?
c = result & 01000000;
¿Cómo se obtiene el valor del bit 6?

"Eso es muy inusual, pero no es difícil. Hombre, ahora soy un programador de primera".

"Y un pequeño consejo más sobre cómo obtener fácilmente números con un bit específico establecido en 0 o 1: 01000000 o 10111111".

Para ello contamos con los  operadores >> << .

"1 es 2 a la potencia cero. En otras palabras, un número con el bit 0 establecido en 1. Necesitamos un número con el bit 6 establecido".

int c = 1 << 6; // 0000 0001 << 6 == 0100 0000 == 64

"¡Genial! Eso es realmente útil para tales casos".

"Pero, ¿qué sucede si necesito un número en el que todos los bits estén configurados en 1, excepto que un bit específico esté configurado en 0?"

"Eso tampoco es difícil:"

int d = ~(1 << 6); // ~0100 0000 == 10111111

"En otras palabras, todo es muy simple:"

Código Descripción
result = result | (1 << 6);
result |= (1 << 6);
¿Cómo se configura el bit 6 a 1?
result = result & ~(1 << 6);
result &= ~(1 << 6);
¿Cómo se configura el bit 6 a 0?
c = result & (1 << 6);
¿Cómo se obtiene el valor del bit 6?

"No parece muy difícil. Pero no lo recordaré de inmediato".

"Pero, si encuentra una expresión aterradora como "resultado &= ~(1 << 6)" en el código de otra persona, sabrá que esa persona solo está trabajando con una máscara de bits".

"Y si lo encuentras a menudo, entonces se recordará por ti".

"Recordar en sí... Eso suena bien. Gracias por la lección".