stringtranslate.com

Operación bit a bit

En programación informática , una operación bit a bit opera sobre una cadena de bits , una matriz de bits o un número binario (considerado como una cadena de bits) al nivel de sus bits individuales . Es una acción rápida y sencilla, básica para las operaciones aritméticas de nivel superior y soportada directamente por el procesador . La mayoría de las operaciones bit a bit se presentan como instrucciones de dos operandos donde el resultado reemplaza uno de los operandos de entrada.

En procesadores simples de bajo costo, normalmente, las operaciones bit a bit son sustancialmente más rápidas que la división, varias veces más rápidas que la multiplicación y, a veces, significativamente más rápidas que la suma. Si bien los procesadores modernos generalmente realizan sumas y multiplicaciones tan rápido como las operaciones bit a bit debido a sus canales de instrucciones más largos y otras opciones de diseño arquitectónico , las operaciones bit a bit comúnmente usan menos energía debido al uso reducido de recursos. [1]

Operadores bit a bit

En las explicaciones siguientes, cualquier indicación de la posición de un bit se cuenta desde el lado derecho (menos significativo), avanzando hacia la izquierda. Por ejemplo, el valor binario 0001 (1 decimal) tiene ceros en todas las posiciones excepto en la primera (es decir, la más a la derecha).

NO

El NOT bit a bit , o complemento bit a bit , es una operación unaria que realiza una negación lógica en cada bit, formando el complemento a unos del valor binario dado. Los bits que son 0 se convierten en 1 y los que son 1 se convierten en 0. Por ejemplo:

NO 0 111 (7 decimal) = 1 000 (8 decimales)
NO 10101011 (decimal 171) = 01010100 (84 decimales)

El resultado es igual al complemento a dos del valor menos uno. Si se utiliza la aritmética en complemento a dos, entonces NOT x = -x − 1.

Para los enteros sin signo , el complemento bit a bit de un número es el "reflejo en espejo" del número en el punto medio del rango del entero sin signo. Por ejemplo, para enteros sin signo de 8 bits, NOT x = 255 - xque se pueden visualizar en un gráfico como una línea descendente que efectivamente "invierte" un rango creciente de 0 a 255 a un rango decreciente de 255 a 0. Un ejemplo simple pero ilustrativo utiliza es invertir una imagen en escala de grises donde cada píxel se almacena como un entero sin signo.

Y

Bit a bit Y de enteros de 4 bits

Un AND bit a bit es una operación binaria que toma dos representaciones binarias de igual longitud y realiza la operación AND lógica en cada par de bits correspondientes. Por tanto, si ambos bits en la posición comparada son 1, el bit en la representación binaria resultante es 1 (1 × 1 = 1); en caso contrario, el resultado es 0 (1 × 0 = 0 y 0 × 0 = 0). Por ejemplo:

 010 1 (5 decimales)Y 001 1 (3 decimal) = 000 1 (1 decimal)

La operación se puede utilizar para determinar si un bit en particular se establece (1) o se borra (0). Por ejemplo, dado un patrón de bits 0011 (3 decimal), para determinar si el segundo bit está establecido usamos un AND bit a bit con un patrón de bits que contiene 1 solo en el segundo bit:

 00 1 1 (3 decimales)Y 00 1 0 (decimal 2) = 00 1 0 (decimal 2)

Debido a que el resultado 0010 no es cero, sabemos que se estableció el segundo bit en el patrón original. A esto se le suele denominar enmascaramiento de bits . (Por analogía, el uso de cinta adhesiva cubre, o máscaras , partes que no deben modificarse o partes que no son de interés. En este caso, los valores 0 enmascaran los bits que no son de interés).

El AND bit a bit se puede utilizar para borrar bits seleccionados (o banderas ) de un registro en el que cada bit representa un estado booleano individual . Esta técnica es una forma eficaz de almacenar varios valores booleanos utilizando la menor cantidad de memoria posible.

Por ejemplo, 0110 (6 decimal) se puede considerar un conjunto de cuatro indicadores, donde el primero y el cuarto indicadores están limpios (0) y el segundo y tercer indicadores están establecidos (1). La tercera bandera se puede borrar usando un AND bit a bit con el patrón que tiene un cero solo en el tercer bit:

 0 1 10 (6 decimales)Y 1 0 11 (11 decimal) = 0 0 10 (2 decimales)

Debido a esta propiedad, resulta fácil verificar la paridad de un número binario verificando el valor del bit de menor valor. Usando el ejemplo anterior:

 0110 (6 decimales)Y 0001 (1 decimal) = 0000 (0 decimal)

Como 6 Y 1 son cero, 6 es divisible por dos y, por lo tanto, par.

O

OR bit a bit de enteros de 4 bits

Un OR bit a bit es una operación binaria que toma dos patrones de bits de igual longitud y realiza la operación OR lógica inclusiva en cada par de bits correspondientes. El resultado en cada posición es 0 si ambos bits son 0, mientras que en caso contrario el resultado es 1. Por ejemplo:

 0 101 (5 decimales)O 0 011 (3 decimal) = 0 111 (7 decimales)

El OR bit a bit se puede utilizar para establecer en 1 los bits seleccionados del registro descrito anteriormente. Por ejemplo, el cuarto bit de 0010 (decimal 2) se puede configurar realizando un OR bit a bit con el patrón con solo el cuarto bit establecido:

 0 0 1 0 (2 decimales)O 1 0 0 0 (8 decimales) = 1 0 1 0 (10 decimales)

XOR

XOR bit a bit de enteros de 4 bits

Un XOR bit a bit es una operación binaria que toma dos patrones de bits de igual longitud y realiza la operación OR lógica exclusiva en cada par de bits correspondientes. El resultado en cada posición es 1 si solo uno de los bits es 1, pero será 0 si ambos son 0 o ambos son 1. En este realizamos la comparación de dos bits, siendo 1 si los dos bits son diferentes, y 0 si son iguales. Por ejemplo:

 0 10 1 (5 decimales)XOR 0 01 1 (3 decimales) = 0 11 0 (6 decimales)

El XOR bit a bit se puede utilizar para invertir bits seleccionados en un registro (también llamado alternar o invertir). Cualquier bit se puede alternar mediante XOR con 1. Por ejemplo, dado el patrón de bits 0010 (2 decimal), el segundo y cuarto bits se pueden alternar mediante un XOR bit a bit con un patrón de bits que contiene 1 en las posiciones segunda y cuarta:

 0 0 1 0 (2 decimales)XOR 1 0 1 0 (decimal 10) = 1 0 0 0 (8 decimales)

Esta técnica se puede utilizar para manipular patrones de bits que representan conjuntos de estados booleanos.

Los programadores de lenguaje ensamblador y los compiladores de optimización a veces usan XOR como un atajo para establecer el valor de un registro en cero. Realizar XOR en un valor contra sí mismo siempre produce cero, y en muchas arquitecturas esta operación requiere menos ciclos de reloj y menos memoria que cargar un valor cero y guardarlo en el registro.

Si el conjunto de cadenas de bits de longitud fija n (es decir, palabras de máquina ) se considera como un espacio vectorial de n dimensiones sobre el campo , entonces la suma de vectores corresponde al XOR bit a bit.

Equivalentes matemáticos

Suponiendo que , para los enteros no negativos, las operaciones bit a bit se pueden escribir de la siguiente manera:

Tabla de verdad para todos los operadores lógicos binarios

Hay 16 posibles funciones de verdad de dos variables binarias ; esto define una tabla de verdad .

Aquí están las operaciones equivalentes bit a bit de dos bits P y Q:

cambios de bits

Los desplazamientos de bits a veces se consideran operaciones bit a bit porque tratan un valor como una serie de bits en lugar de una cantidad numérica. En estas operaciones, los dígitos se mueven o desplazan hacia la izquierda o hacia la derecha. Los registros en el procesador de una computadora tienen un ancho fijo, por lo que algunos bits se "desplazarán hacia afuera" del registro en un extremo, mientras que el mismo número de bits se "desplazarán hacia adentro" desde el otro extremo; Las diferencias entre los operadores de desplazamiento de bits radican en cómo determinan los valores de los bits desplazados.

Direccionamiento de bits

Si el ancho del registro (frecuentemente 32 o incluso 64) es mayor que el número de bits (generalmente 8) de la unidad direccionable más pequeña, frecuentemente llamada byte, las operaciones de desplazamiento inducen un esquema de direccionamiento de bytes a bits. De este modo, las orientaciones "izquierda" y "derecha" se toman de la escritura estándar de números en notación de valor posicional , de modo que un desplazamiento hacia la izquierda aumenta y un desplazamiento hacia la derecha disminuye el valor del número; si los dígitos de la izquierda se leen primero, esto constituye una orientación big-endian . Sin tener en cuenta los efectos de los límites en ambos extremos del registro, las operaciones de desplazamiento aritmético y lógico se comportan de la misma manera, y un desplazamiento de 8 posiciones de bits transporta el patrón de bits en una posición de 1 byte de la siguiente manera:

desplazamiento aritmético

Desplazamiento aritmético hacia la izquierda
desplazamiento aritmético a la derecha

En un desplazamiento aritmético , los bits que se desplazan fuera de cualquiera de los extremos se descartan. En un desplazamiento aritmético hacia la izquierda, los ceros se desplazan hacia la derecha; en un desplazamiento aritmético a la derecha, el bit de signo (el MSB en complemento a dos) se desplaza hacia la izquierda, preservando así el signo del operando.

Este ejemplo utiliza un registro de 8 bits, interpretado como complemento a dos:

 00010111 (decimal +23) SHIFT IZQUIERDA= 0010111 0 (decimal +46)
 10010111 (decimal −105) DESPLAZAMIENTO A LA DERECHA= 1 1001011 (decimal −53)

En el primer caso, el dígito más a la izquierda se desplazó más allá del final del registro y un nuevo 0 se desplazó a la posición más a la derecha. En el segundo caso, el 1 más a la derecha se desplazó hacia afuera (quizás hacia la bandera de acarreo ) y se copió un nuevo 1 en la posición más a la izquierda, conservando el signo del número. A veces, los turnos múltiples se reducen a un solo turno en una cierta cantidad de dígitos. Por ejemplo:

 00010111 (decimal +23) DESPLAZAMIENTO A LA IZQUIERDA POR DOS= 010111 00 (decimal +92)

Un desplazamiento aritmético a la izquierda de n equivale a multiplicar por 2 n (siempre que el valor no se desborde ), mientras que un desplazamiento aritmético a la derecha de n de un valor en complemento a dos equivale a tomar el suelo de la división por 2 n . Si el número binario se trata como complemento a uno , entonces la misma operación de desplazamiento a la derecha da como resultado la división por 2 n y el redondeo hacia cero .

cambio lógico

En un desplazamiento lógico , se desplazan ceros para reemplazar los bits descartados. Por lo tanto, los desplazamientos a la izquierda lógicos y aritméticos son exactamente iguales.

Sin embargo, como el desplazamiento lógico a la derecha inserta bits de valor 0 en el bit más significativo, en lugar de copiar el bit de signo, es ideal para números binarios sin signo, mientras que el desplazamiento aritmético a la derecha es ideal para números binarios en complemento a dos con signo.

cambio circular

Otra forma de desplazamiento es el desplazamiento circular , rotación bit a bit o rotación de bits .

Girar

En esta operación, a veces llamada rotar sin acarreo , los bits se "rotan" como si los extremos izquierdo y derecho del registro estuvieran unidos. El valor que se desplaza hacia la derecha durante un desplazamiento hacia la izquierda es cualquier valor que se desplaza hacia la izquierda, y viceversa para una operación de desplazamiento hacia la derecha. Esto es útil si es necesario conservar todos los bits existentes y se utiliza con frecuencia en criptografía digital . [ se necesita aclaración ]

Girar mediante transporte

Rotar mediante acarreo es una variante de la operación de rotación, donde el bit que se desplaza hacia adentro (en cualquier extremo) es el valor anterior de la bandera de acarreo, y el bit que se desplaza hacia afuera (en el otro extremo) se convierte en el nuevo valor de la bandera de acarreo.

Una sola rotación a través del acarreo puede simular un cambio lógico o aritmético de una posición configurando la bandera de acarreo de antemano. Por ejemplo, si el indicador de acarreo contiene 0, entonces x RIGHT-ROTATE-THROUGH-CARRY-BY-ONEes un desplazamiento lógico a la derecha, y si el indicador de acarreo contiene una copia del bit de signo, entonces x RIGHT-ROTATE-THROUGH-CARRY-BY-ONEes un desplazamiento aritmético a la derecha. Por esta razón, algunos microcontroladores, como los PIC de gama baja, simplemente rotan y rotan mediante carry y no se molestan con instrucciones de cambio aritméticas o lógicas.

La rotación mediante acarreo es especialmente útil cuando se realizan desplazamientos en números mayores que el tamaño de palabra nativo del procesador , porque si se almacena un número grande en dos registros, el bit que se desplaza de un extremo del primer registro debe entrar en el otro extremo del el segundo. Con la rotación mediante acarreo, esa broca se "guarda" en la bandera de acarreo durante el primer turno, lista para cambiar durante el segundo turno sin ninguna preparación adicional.

En lenguajes de alto nivel

En la familia de lenguajes C.

En los lenguajes C y C++, los operadores de desplazamiento lógicos son " <<" para desplazamiento a la izquierda y " >>" para desplazamiento a la derecha. El número de lugares a cambiar se proporciona como segundo argumento al operador. Por ejemplo,

x = y << 2 ;    

Asigna xel resultado de desplazarse yhacia la izquierda dos bits, lo que equivale a una multiplicación por cuatro.

Los cambios pueden dar como resultado un comportamiento definido por la implementación o un comportamiento indefinido , por lo que se debe tener cuidado al usarlos. El resultado de cambiar un número de bits mayor o igual al tamaño de la palabra es un comportamiento indefinido en C y C++. [2] [3] Desplazar un valor negativo a la derecha está definido por la implementación y no lo recomiendan las buenas prácticas de codificación; [4] el resultado de desplazar hacia la izquierda un valor con signo no está definido si el resultado no se puede representar en el tipo de resultado. [2]

En C#, el desplazamiento a la derecha es un desplazamiento aritmético cuando el primer operando es int o long. Si el primer operando es de tipo uint o ulong, el desplazamiento a la derecha es un desplazamiento lógico. [5]

Turnos circulares

La familia de lenguajes C carece de un operador de rotación (aunque C++ 20 proporciona std::rotly std::rotr), pero se puede sintetizar uno a partir de los operadores de cambio. Se debe tener cuidado para garantizar que la declaración esté bien formada para evitar comportamientos indefinidos y ataques de sincronización en software con requisitos de seguridad. [6] Por ejemplo, una implementación ingenua que rota a la izquierda un valor sin signo de 32 bits xpor nposiciones es simplemente

uint32_t x = ..., n = ...; uint32_t y = ( x << n ) | ( x >> ( 32 - norte ));                 

Sin embargo, un desplazamiento de 0bits da como resultado un comportamiento indefinido en la expresión de la derecha (x >> (32 - n))porque 32 - 0es 32y 32está fuera del rango 0–31 inclusive. Un segundo intento podría resultar en

uint32_t x = ..., n = ...; uint32_t y = n ? ( x << norte ) | ( x >> ( 32 - n ) ) : x ;                     

donde se prueba la cantidad de cambio para garantizar que no introduzca un comportamiento indefinido. Sin embargo, la rama agrega una ruta de código adicional y presenta una oportunidad para realizar análisis y ataques de tiempo, lo que a menudo no es aceptable en software de alta integridad. [6] Además, el código se compila en múltiples instrucciones de máquina, lo que a menudo es menos eficiente que la instrucción nativa del procesador.

Para evitar el comportamiento indefinido y las ramas en GCC y Clang , se recomienda lo siguiente. Muchos compiladores reconocen el patrón y el compilador emitirá una única instrucción de rotación: [7] [8] [9]

uint32_t x = ..., n = ...; uint32_t y = ( x << n ) | ( x >> ( - n & 31 ));                 

También hay intrínsecos específicos del compilador que implementan cambios circulares , como _rotl8, _rotl16, _rotr8, _rotr16 en Microsoft Visual C++ . Clang proporciona algunos elementos intrínsecos de rotación para la compatibilidad con Microsoft que sufre los problemas anteriores. [9] GCC no ofrece funciones intrínsecas de rotación. Intel también proporciona elementos intrínsecos x86.

Java

En Java , todos los tipos de enteros tienen signo, por lo que los operadores " <<" y " >>" realizan desplazamientos aritméticos. Java agrega el operador " >>>" para realizar desplazamientos lógicos a la derecha, pero dado que las operaciones lógicas y aritméticas de desplazamiento a la izquierda son idénticas para enteros con signo, no existe un <<<operador " " en Java.

Más detalles de los operadores de turnos de Java: [10]

javascript

JavaScript utiliza operaciones bit a bit para evaluar cada una de dos o más unidades y colocarlas en 1 o 0. [12]

Pascal

En Pascal, así como en todos sus dialectos (como Object Pascal y Standard Pascal ), los operadores lógicos de desplazamiento hacia la izquierda y hacia la derecha son " shl" y " shr", respectivamente. Incluso para enteros con signo, shrse comporta como un desplazamiento lógico y no copia el bit de signo. El número de lugares a cambiar se da como segundo argumento. Por ejemplo, lo siguiente asigna a x el resultado de desplazar y hacia la izquierda dos bits:

x := y shl 2 ;    

Otro

Aplicaciones

Las operaciones bit a bit son necesarias particularmente en programación de nivel inferior, como controladores de dispositivos, gráficos de bajo nivel, ensamblaje de paquetes de protocolos de comunicaciones y decodificación.

Aunque las máquinas suelen tener instrucciones integradas eficientes para realizar operaciones aritméticas y lógicas, todas estas operaciones se pueden realizar combinando operadores bit a bit y pruebas cero de varias maneras. [13] Por ejemplo, aquí hay una implementación de pseudocódigo de la multiplicación del antiguo Egipto que muestra cómo multiplicar dos números enteros arbitrarios ay b( amayor que b) usando solo cambios de bits y suma:

c 0 mientras b 0 si ( b y 1 ) 0 c c + a desplazar a la izquierda a en 1 desplazar a la derecha b en 1 regresar c                           

Otro ejemplo es una implementación de pseudocódigo de suma, que muestra cómo calcular una suma de dos números enteros ay butiliza operadores bit a bit y pruebas de cero:

mientras que a 0 c b y a b b xor a desplazamiento a la izquierda c por 1 a c devolver b                      

álgebra de Boole

A veces resulta útil simplificar expresiones complejas formadas por operaciones bit a bit, por ejemplo al escribir compiladores. El objetivo de un compilador es traducir un lenguaje de programación de alto nivel al código de máquina más eficiente posible. El álgebra booleana se utiliza para simplificar expresiones bit a bit complejas.

Y

O

NO

XOR

Además, XOR se puede componer utilizando las 3 operaciones básicas (Y, O, NO)

Otros

Inversas y resolución de ecuaciones.

Puede resultar difícil resolver variables en álgebra booleana porque, a diferencia del álgebra regular, varias operaciones no tienen inversas. Las operaciones sin inversas pierden algunos de los bits de datos originales cuando se realizan y no es posible recuperar esta información faltante.

Orden de operaciones

Las operaciones que se encuentran en la parte superior de esta lista se ejecutan primero. Consulte el artículo principal para obtener una lista más completa.

Ver también

Referencias

  1. ^ "Blog de diseño de bajo consumo de CMicrotek". CMicrotek . Consultado el 12 de agosto de 2015 .
  2. ^ ab JTC1/SC22/WG14 N843 "Lenguaje de programación C", sección 6.5.7
  3. ^ "Operadores aritméticos - cppreference.com". es.cppreference.com . Consultado el 6 de julio de 2016 .
  4. ^ "INT13-C. Utilice operadores bit a bit sólo en operandos sin signo". CERT: Estándares de codificación segura . Instituto de Ingeniería de Software, Universidad Carnegie Mellon . Consultado el 7 de septiembre de 2015 .
  5. ^ "Operador (referencia de C#)". Microsoft . Consultado el 14 de julio de 2013 .
  6. ^ ab "¿Rotación de tiempo casi constante que no viola los estándares?". Red de intercambio de pila . Consultado el 12 de agosto de 2015 .
  7. ^ "Mala optimización del lenguaje de rotación portátil". Proyecto GNU GCC . Consultado el 11 de agosto de 2015 .
  8. ^ "¿Rotación circular que no viola el estándar C/C++?". Foros de desarrolladores de Intel . Consultado el 12 de agosto de 2015 .
  9. ^ ab "La constante no se propaga al ensamblaje en línea, lo que da como resultado" la restricción 'I' espera una expresión constante entera"". Proyecto LLVM . Consultado el 11 de agosto de 2015 .
  10. ^ La especificación del lenguaje Java, sección 15.19. Operadores de turno
  11. ^ ab "Capítulo 15. Expresiones". oracle.com .
  12. ^ "JavaScript bit a bit". W3Schools.com .
  13. ^ "Sintetizar operaciones aritméticas mediante trucos de desplazamiento de bits". Bisqwit.iki.fi. 2014-02-15 . Consultado el 8 de marzo de 2014 .
  14. ^ A lo largo de este artículo, 0xFFFF significa que todos los bits de su tipo de datos deben establecerse en 1. La cantidad exacta de bits depende del ancho del tipo de datos.
  15. ^ - aquí se trata de negación, no de resta.
  16. ^ - aquí es resta, no negación

enlaces externos