Trucos avanzados de operaciones a nivel de bits

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

Etiquetas: operaciones-bits optimización algoritmos binary low-level

Publicado el 6-2 20:29