Este artículo recopila técnicas útiles para manipular datos a nivel de bits, permitiendo optimizar algoritmos y resolver problemas de manera eficiente.
1. Verificar igualdad de signo
Para determinar si dos números enteros comparten el mismo signo (positivo/negativo):
bool mismoSigno = (a ^ b) >= 0;
2. Promedio seguro sin desbordamiento
Calcular el promedio de dos enteros evitendo errores por desbordamiento:
int promedio = (x + y) >> 1;
3. Detección par/impar mediante máscara
Evaluar paridad usando la operación AND:
bool esPar = (numero & 1) == 0;
4. Comprobación de potencias de dos
Verificar si un entero es potencia exacta de dos:
bool esPotenciaDos = (valor & (valor - 1)) == 0 && valor != 0;
5. Función signo mediante desplazamiento
Obtener 1 para positivos y -1 para negativos en enteros de 32 bits:
int signo = (num >> 31) | 1;
6. Índice del primer bit activo con secuencia De Bruijn
Identificar la posición del bit más bajo establecido usendo aritmética mágica:
int[] tablaPosiciones = {
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
uint mascara = 1u << 7;
uint factor = 0x077CB531u;
int posicionBit = tablaPosiciones[((mascara & (uint)-mascara) * factor) >> 27];
7. Multiplicación/división mediante desplazamientos
Desplazamiento izquierdo equivale a multiplicar por potencias de dos:
int resultado = 3 << 2; // Equivale a 3 * 4
Desplazamiento derecho actúa como división entera por potencias de dos:
<cocodigo>int cociente = 16 >> 3; // Equivale a 16 / 8</cocodigo>
8. Rotación circular de bits
Implementar rotación dentro del tamaño del tipo de dato:
byte RotarBits(byte dato, bool izquierda)
{
uint temp = dato;
temp <<= 8;
if (izquierda)
{
temp |= dato;
temp <<= 1;
}
else
{
uint mascaraBits = (uint)dato << 16;
temp |= mascaraBits;
temp >>= 1;
}
uint filtro = 0b_0000_0000____0000_0000____1111_1111____0000_0000;
temp &= filtro;
temp >>= 8;
return (byte)temp;
}
9. Eliminar el bit activo más a la derecha
Quitar el último bit 1 encontrado desde el final:
int limpio = numero & (numero - 1);
10. Aislar el primer bit activo
Extraer únicamente el bit 1 más bajo:
int bitMenor = numero & (-numero);
11. Verificar si todos los bits están activados
Comprobar si un valor binario tiene solo unos:
bool todosBits = (valor & (valor + 1)) == 0;
12. Rellenar hacia la derecha desde el primer bit activo
Establecer todos los bits a la derecha del primer 1 encontrado:
int rellenado = numero | (numero - 1);
13. Suma binaria mediante operación XOR
La operación exclusiva puede modelar la adición sin considerar acarreo:
int parcial = a ^ b; // Suma sin acarreo