Una operación bit a bit o bitwise opera sobre números binarios a nivel de sus bits individuales. Es una acción primitiva rápida, soportada directamente por los procesadores. En procesadores simples de bajo costo, las operaciones de bit a bit, junto con los de adición y sustracción, son típicamente sustancialmente más rápidas que la multiplicación y la división, mientras que en los modernos procesadores de alto rendimiento usualmente las operaciones se realizan casi a la misma velocidad.
Tipos de operaciones
Operaciones bit a bit: Ejecutan las operaciones lógicas AND, OR, XOR, NOT, etc, sobre los bits individuales de los operandos. Operaciones de desplazamiento: Desplazan los bits de los operandos hacia la derecha o hacia la izquierda una o más posiciones. Operaciones de rotación: Rotan los bits del operando hacia la derecha o hacia la izquierda una o más posiciones. Pueden usar o no el flag del acarreo como un bit adicional en la rotación.
Operadores bit a bit
En las explicaciones de abajo, cualquier indicación de una posición de un bit es contada de derecha a izquierda a partir del bit menos significativo. Por ejemplo, el valor binario 0001 (el decimal 1) tiene ceros en cada posición excepto en la primera.
NOT
A NOT A0 11 0
El NOT bit a bit, o bitwise, o complemento, es una operación unaria que realiza la negación lógica en cada bit, invirtiendo los bits del número, de tal manera que los ceros se convierten en 1 y viceversa. Por ejemplo:
NOT 10011 = 01100
El NOT forma el complemento a uno de un valor binario dado. En un número entero con signo en complemento a dos, el NOT da como resultado el inverso aditivo del número menos 1, es decir NOT x = -x - 1. Para obtener el complemento a dos de un número, se debe sumar 1 al resultado, dando el negativo del número. Esto equivale a un cambio de signo del número: +5 se convierte en -5, y -5 se convierte en +5. Para los enteros sin signo, el complemento bit a bit es la “reflexión de espejo” del número a través del punto medio del rango del entero. Por ejemplo, para los enteros sin signo de 8 bits, NOT x = 255 - x, para los enteros sin signo de 16 bits, NOT x = 65535 - x, y en general, para los enteros sin signo de n bits, NOT x = (2n - 1) - x.
AND
A B A AND B0 0 00 1 01 0 01 1 1
El AND bit a bit, o bitwise, toma dos números enteros y realiza la operación AND lógica en cada par correspondiente de bits. El resultado en cada posición es 1 si el bit correspondiente de los dos operandos es 1, y 0 de lo contrario, por ejemplo:
0101 AND 0011 = 0001
El AND puede ser usado para filtrar determinados bits, permitiendo que unos bits pasen y los otros no. También puede usarse en sistemas de mayor fiabilidad.
Determinando el estado de bits
El AND puede ser usado para determinar si un bit particular está encendido (1) o apagado (0). Por ejemplo, dado un patrón de bits 0011, para determinar si el segundo bit está encendido se usa una operación AND con una máscara que contiene encendido solo el segundo bit, que es el que se quiere determinar:
0011 AND 0010 (máscara) = 0010
Puesto que el resultado 0010 es diferente de cero, se sabe que el segundo bit en el patrón original está encendido. Esto es a menudo llamado enmascaramiento del bit (bit masking). (Por analogía, al uso de las cintas de enmascarar, que cubren o enmascaran porciones que no deben ser alteradas o porciones que no son de interés. En este caso, los valores 0 enmascaran los bits que no son de interés).
Extrayendo bits
El AND se puede usar para extraer determinados bits de un valor. Si en un byte, por ejemplo, tenemos representados dos dígitos hexadecimales empaquetados, (uno en los 4 bits superiores y el otro en los 4 bits inferiores), podemos extraer cada dígito hexadecimal usando el AND con las máscaras adecuadas:
0011 0101 0011 0101 AND 1111 0000 (máscara) AND 0000 1111 (máscara) = 0011 0000 = 0000 0101 Hex. superior Hex. inferior
Apagando bits
El AND también se puede usar para apagar determinados bits. Solo hay que poner una máscara con bits en cero en las posiciones de los bits que se quieren apagar y 1 en los demás bits. Todos los demás bits con la máscara 1 pasarán inalterados, y los que tienen la máscara 0 se apagarán. Dado el ejemplo 0111, el segundo bit puede ser apagado usando un AND con el patrón que tiene un cero en el segundo bit y un 1 en el resto de los bits:
0111 AND 1101 (máscara) = 0101
OR
A B A OR B0 0 00 1 11 0 11 1 1
Una operación OR de bit a bit, o bitwise, toma dos números enteros y realiza la operación OR inclusivo en cada par correspondiente de bits. El resultado en cada posición es 1 si el bit correspondiente de cualquiera de los dos operandos es 1, y 0 si ambos bits son 0, por ejemplo:
0101 OR 0011 = 0111
Encendiendo bits
El OR bit a bit, o bitwise, puede ser usado para encender un bit individual o un conjunto de bits. Para ello se usa una máscara OR con los bits que se quieren encender en 1 y el resto de los bits en cero. El resultado será que todos los bits originales quedarán como estaban excepto los bits en donde la máscara tenga 1, que resultarán encendidos. Por ejemplo, si en el patrón de bits 0101 se quiere encender el segundo bit se hará de la manera siguiente:
0101 OR 0010 (máscara) = 0111
Copiando bits
El OR, y el desplazamiento lógico (explicado más adelante), puede ser usado para copiar un grupo de bits a una posición determinada.
Supongamos que tenemos el signo, el exponente, y la parte significativa de un número, en diferentes registros de 32 bits, y queremos empaquetarlos para formar un número en representación de punto flotante de simple precisión de 32 bits:
Signo: 00000000000000000000000000000001 Exponente: 00000000000000000000000010000011 Parte significativa: 00000000011100000111000000001110
Todos ellos tienen los valores correctos y tenemos que mover cada uno de ellos a su posición para poder armar el punto flotante.
Se debe mover el signo 31 posiciones hacia la izquierda, el exponente 23 posiciones hacia la izquierda, y la parte significativa no es necesaria moverla porque ya está en la posición correcta. Estos desplazamientos se hacen con la operación de desplazamiento hacia la izquierda descrito más adelante:
Signo: 10000000000000000000000000000000 <-- Se desplaza el signo 31 posiciones hacia la izquierda Exponente: 01000001100000000000000000000000 <-- Se desplaza el exponente 23 posiciones hacia la izquierda Parte significativa: 00000000011100000111000000001110 <-- La parte significativa no se mueve, ya está en su lugar
Ahora que tenemos cada parte del número en su lugar, las combinamos para empaquetarlas y formar el número en su representación de punto flotante de 32 bits. Para ello usamos el OR: (Resultado final) = (Signo) OR (Exponente) OR (Parte significativa):
Signo: 10000000000000000000000000000000 Exponente: 01000001100000000000000000000000 Parte significativa: 00000000011100000111000000001110 Resultado final: 11000001111100000111000000001110
Ya tenemos el número en su representación de punto flotante definitiva.
Procedimiento genérico para copiar un grupo de bits
Para copiar una serie de bits en un lugar determinado usando OR, se necesita que ese lugar donde se van a copiar tenga sus bits en cero (para hacer un espacio libre para poder copiar los bits). También se necesita que el registro donde se encuentran los bits que se quieren copiar tenga los demás bits (los que no se quieren copiar) apagados. Ambas operaciones, aclarar los bits en el lugar del destino, y aclarar los bits que no se quieren copiar se hacen con AND:
Tenemos dos registros de 16 bits:
Registro A: 1011 1100 0110 1100 Registro B: 1001 0001 1111 1010
Queremos copiar los cuatro bits menos significativos del registro A en el registro B.
Para ello, primero aclaramos los 4 bits menos significativos de B con una operación AND, y así tener un espacio libre:
1001 0001 1111 1010 <-- Valor original del registro B AND 1111 1111 1111 0000 <-- Máscara para aclarar los bits de B donde se van a copiar los que vienen de A = 1001 0001 1111 0000 <-- Registro B preparado para recibir los 4 bits menos significativos de A
Luego, aclaramos los bits de A que no queremos copiar, dejando solo los bits que queremos copiar:
1011 1100 0110 1100 <-- Valor original del registro A AND 0000 0000 0000 1111 <-- Máscara para dejar solo los bits de A que se quieren copiar = 0000 0000 0000 1100 <-- Registro A con solo los bits que se desean copiar
Ahora estamos listos para hacer el OR de A sobre B y combinar los 4 bits menos significativos de A sobre B:
0000 0000 0000 1100 <-- Registro A con los 4 bits que se desean copiar OR 1001 0001 1111 0000 <-- Registro B con un espacio para los 4 bits que desean copiar = 1001 0001 1111 1100 <-- Registro B con los 4 bits menos significativos de A copiados sobre él
Ahora, el registro B tiene copiado los 4 bits menos significativos de A. El resto de los bits de B quedaron intactos.
XOR
A B A XOR B0 0 00 1 11 0 11 1 0
El XOR bit a bit, o bitwise, toma dos números enteros y realiza la operación OR exclusivo en cada par correspondiente de bits. El resultado en cada posición es 1 si el par de bits son diferentes y cero si el par de bits son iguales. Por ejemplo:
0101 XOR 0011 = 0110
Invirtiendo bits selectivamente
A diferencia del NOT, que invierte todos los bits de un registro, el XOR bit a bit, o bitwise, puede ser usado para invertir selectivamente uno o más bits en un registro. Dado el patrón de bits 0011, el segundo y el cuarto bit pueden ser invertidos por XOR con una máscara con un patrón de bits conteniendo 1 en las posiciones que se quieren invertir, la segunda y cuarta, y 0 en las demás. Los bits de las posiciones con cero de la máscara resultarán inalterados:
0011 XOR 1010 (máscara) = 1001
Igualdad y desigualdad de bits
XOR es equivalente y tiene la misma tabla de verdad que la desigualdad, XOR y desigualdad son sinónimos:
A B A XOR B A <> B0 0 0 00 1 1 11 0 1 11 1 0 0
El XOR puede usarse para saber si los bits correspondientes de dos operandos son iguales o diferentes. Por ejemplo, si tenemos dos operandos, 1000 y 0010 y queremos saber si los bits más significativos de ambos son iguales procedemos como sigue:
1000 XOR 0010 = 1010
Ahora, cada bit del resultado estará en 0 si el bit correspondiente de los dos operandos son iguales, y en 1 si son diferentes. El bit más significativo del resultado está en 1 indicando que son diferentes, pero tenemos que aislarlo de los demás con un AND para poder usarlo o tomar una decisión:
1010 (resultado anterior) AND 1000 (máscara para aislar el bit más significativo) = 1000
Ahora lo tenemos aislado en el resultado final, que es diferente de cero indicando que los bits más significativo de los operandos son diferentes.
Asignar cero a un registro
Los programadores avanzados de lenguaje ensamblador usan XOR como una manera eficiente y rápida de asignar cero a un registro. Realizar XOR de un valor contra sí mismo siempre resulta en cero (A XOR A siempre es cero), y en muchas arquitecturas esta operación requiere menos ciclos de reloj y/o memoria que cargar un valor cero a un registro (A = 0).
En resumen
Las operaciones bit a bit, o bitwise, pueden encender, apagar, dejar pasar, eliminar, o invertir, bits individualmente o en conjunto, usando la máscara adecuada con un OR, AND, o XOR:
0011 1011 10101 10101 1010 OR 1000 (máscara) AND 1110 (máscara) AND 00111 (máscara) AND 11000 (máscara) XOR 1001 (máscara) = 1011 = 1010 = 00101 = 10000 = 0011 Enciende el Apaga el Deja pasar los 3 Elimina los 3 Invierte los bits bit superior bit inferior bits inferiores bits inferiores inferior y superior
NOT invierte los bits y XOR junto con AND permiten determinar si dos operandos tienen los bits de una determinada posición iguales o diferentes:
NOT 1011 11010 = 0100 XOR 10100 invierte todos = 01110 (0 = bit iguales, 1 = bits diferentes)