Considere este código:
x = 1 # 0001
x << 2 # Shift left 2 bits: 0100
# Result: 4
x | 2 # Bitwise OR: 0011
# Result: 3
x & 1 # Bitwise AND: 0001
# Result: 1
Puedo entender los operadores aritméticos en Python (y otros lenguajes), pero nunca entendí bien los operadores 'bit a bit'. En el ejemplo anterior (de un libro de Python), entiendo el desplazamiento a la izquierda pero no los otros dos.
Además, ¿para qué se utilizan realmente los operadores bit a bit? Agradecería algunos ejemplos.
Respuestas:
Los operadores bit a bit son operadores que trabajan con valores de varios bits, pero conceptualmente un bit a la vez.
AND
es 1 solo si ambas entradas son 1; de lo contrario, es 0.OR
es 1 si una o ambas entradas son 1; de lo contrario, es 0.XOR
es 1 solo si exactamente una de sus entradas es 1, de lo contrario es 0.NOT
es 1 solo si su entrada es 0, de lo contrario es 0.Suelen mostrarse mejor como tablas de verdad. Las posibilidades de entrada están en la parte superior e izquierda, el bit resultante es uno de los cuatro (dos en el caso de NOT, ya que solo tiene una entrada) valores que se muestran en la intersección de las entradas.
Un ejemplo es si solo desea los 4 bits inferiores de un entero, lo Y con 15 (binario 1111), así:
En ese caso, los bits cero en 15 actúan efectivamente como un filtro, lo que obliga a que los bits del resultado también sean cero.
Además,
>>
y<<
menudo se incluyen como operadores bit a bit, y "desplazan" un valor respectivamente a la derecha y a la izquierda en un cierto número de bits, desechando los bits que se mueven del final hacia el que se está desplazando y alimentando bits cero en el Otro final.Así por ejemplo:
Tenga en cuenta que el desplazamiento a la izquierda en Python es inusual porque no usa un ancho fijo donde se descartan los bits; mientras que muchos lenguajes usan un ancho fijo según el tipo de datos, Python simplemente expande el ancho para atender bits adicionales. Para obtener el comportamiento de descarte en Python, puede seguir un desplazamiento a la izquierda con un bit a bit
and
, como en un valor de 8 bits desplazando cuatro bits a la izquierda:Con eso en mente, otro ejemplo de operadores bit a bit es si tiene dos valores de 4 bits que desea empaquetar en uno de 8 bits, puede usar los tres de sus operadores (
left-shift
,and
yor
):& 15
operación se asegurará de que ambos valores solo tengan los 4 bits inferiores.<< 4
es un desplazamiento de 4 bits a la izquierda para moverseval1
en la parte superior 4 bits de un valor de 8 bits.|
simplemente combina estos dos juntos.Si
val1
es 7 yval2
es 4:fuente
Un uso típico:
|
se usa para establecer un cierto bit en 1&
se usa para probar o borrar un cierto bitEstablezca un bit (donde n es el número de bit y 0 es el bit menos significativo):
unsigned char a |= (1 << n);
Borrar un poco:
unsigned char b &= ~(1 << n);
Alternar un poco:
unsigned char c ^= (1 << n);
Prueba un poco:
unsigned char e = d & (1 << n);
Tome el caso de su lista, por ejemplo:
x | 2
se utiliza para establecer el bit 1 dex
en 1x & 1
se utiliza para probar si el bit 0 dex
es 1 o 0fuente
Uno de los usos más comunes de las operaciones bit a bit es para analizar colores hexadecimales.
Por ejemplo, aquí hay una función de Python que acepta una cadena como
#FF09BE
y devuelve una tupla de sus valores rojo, verde y azul.Sé que hay formas más eficientes de lograr esto, pero creo que este es un ejemplo realmente conciso que ilustra tanto los cambios como las operaciones booleanas bit a bit.
fuente
Creo que la segunda parte de la pregunta:
Solo se ha abordado parcialmente. Estos son mis dos centavos al respecto.
Las operaciones bit a bit en lenguajes de programación juegan un papel fundamental cuando se trata de una gran cantidad de aplicaciones. Casi toda la computación de bajo nivel debe realizarse utilizando este tipo de operaciones.
En todas las aplicaciones que necesitan enviar datos entre dos nodos, como:
Red de computadoras;
aplicaciones de telecomunicaciones (teléfonos móviles, comunicaciones por satélite, etc.).
En la capa de comunicación de nivel inferior, los datos generalmente se envían en lo que se denomina tramas . Las tramas son solo cadenas de bytes que se envían a través de un canal físico. Estos marcos generalmente contienen los datos reales más algunos otros campos (codificados en bytes) que son parte de lo que se llama encabezado . El encabezado generalmente contiene bytes que codifican alguna información relacionada con el estado de la comunicación (por ejemplo, con banderas (bits)), contadores de tramas, códigos de corrección y detección de errores, etc. Para obtener los datos transmitidos en una trama y construir marcos para enviar datos, necesitará operaciones seguras a nivel de bits.
En general, cuando se trata de ese tipo de aplicaciones, hay una API disponible para que no tenga que ocuparse de todos esos detalles. Por ejemplo, todos los lenguajes de programación modernos proporcionan bibliotecas para conexiones de socket, por lo que en realidad no necesita construir los marcos de comunicación TCP / IP. Pero piense en las buenas personas que programaron esas API para usted, seguro que tuvieron que lidiar con la construcción de marcos; utilizando todo tipo de operaciones bit a bit para ir y venir de la comunicación de bajo nivel a la de nivel superior.
Como ejemplo concreto, imagine que alguien le da un archivo que contiene datos sin procesar que fueron capturados directamente por hardware de telecomunicaciones. En este caso, para encontrar los fotogramas, deberá leer los bytes sin procesar en el archivo e intentar encontrar algún tipo de palabras de sincronización, escaneando los datos bit a bit. Después de identificar las palabras de sincronización, necesitará obtener los fotogramas reales y CAMBIARlos si es necesario (y ese es solo el comienzo de la historia) para obtener los datos reales que se están transmitiendo.
Otra familia de aplicaciones de bajo nivel muy diferente es cuando necesita controlar el hardware usando algún tipo de puertos (antiguos), como puertos paralelos y seriales. Estos puertos se controlan estableciendo algunos bytes, y cada bit de esos bytes tiene un significado específico, en términos de instrucciones, para ese puerto (consulte, por ejemplo, http://en.wikipedia.org/wiki/Parallel_port ). Si desea crear software que haga algo con ese hardware, necesitará operaciones bit a bit para traducir las instrucciones que desea ejecutar a los bytes que el puerto comprende.
Por ejemplo, si tiene algunos botones físicos conectados al puerto paralelo para controlar algún otro dispositivo, esta es una línea de código que puede encontrar en la aplicación software:
Espero que esto contribuya.
fuente
Espero que esto aclare esos dos:
fuente
x & 1
no ilustra el efecto tan bien como lox & 2
haría.Piense en 0 como falso y 1 como verdadero. Luego, bit a bit y (&) yo (|) funcionan igual que los normales yo, excepto que hacen todos los bits del valor a la vez. Por lo general, verá que se usan para banderas si tiene 30 opciones que se pueden configurar (por ejemplo, como estilos de dibujo en una ventana) y no quiere tener que pasar 30 valores booleanos separados para configurar o desarmar cada uno, por lo que usa | para combinar opciones en un solo valor y luego use & para verificar si cada opción está configurada. Este estilo de paso de bandera es muy utilizado por OpenGL. Como cada bit es una bandera separada, obtienes valores de bandera en potencias de dos (también conocidos como números que tienen solo un bit establecido) 1 (2 ^ 0) 2 (2 ^ 1) 4 (2 ^ 2) 8 (2 ^ 3) el el poder de dos le dice qué bit se establece si la bandera está encendida.
También tenga en cuenta 2 = 10, por lo que x | 2 es 110 (6) no 111 (7) Si ninguno de los bits se superpone (lo cual es cierto en este caso) | actúa como una adición.
fuente
No lo vi mencionado anteriormente, pero también verá que algunas personas usan el desplazamiento a la izquierda y a la derecha para operaciones aritméticas. Un desplazamiento a la izquierda por x equivale a multiplicar por 2 ^ x (siempre que no se desborde) y un desplazamiento a la derecha equivale a dividir por 2 ^ x.
Recientemente, he visto personas que usan x << 1 yx >> 1 para duplicar y reducir a la mitad, aunque no estoy seguro de si solo están tratando de ser inteligentes o si realmente hay una ventaja clara sobre los operadores normales.
fuente
Conjuntos
Los conjuntos se pueden combinar mediante operaciones matemáticas.
|
combina dos conjuntos para formar uno nuevo que contiene elementos en cualquiera.&
obtiene elementos solo en ambos.-
obtiene elementos en el primer conjunto pero no en el segundo.^
obtiene elementos en cualquiera de los conjuntos, pero no en ambos.Inténtalo tú mismo:
Resultado:
fuente
Este ejemplo le mostrará las operaciones para los cuatro valores de 2 bits:
Aquí hay un ejemplo de uso:
fuente
Otro caso de uso común es manipular / probar permisos de archivos. Consulte el módulo de estadísticas de Python: http://docs.python.org/library/stat.html .
Por ejemplo, para comparar los permisos de un archivo con un conjunto de permisos deseado, puede hacer algo como:
Lanzo los resultados como booleanos, porque solo me importa la verdad o la falsedad, pero sería un ejercicio valioso imprimir los valores bin () para cada uno.
fuente
not bool((mode ^ desired_mode) & 0777)
. O (más fácil de entender):not (mode & 0777) ^ desired_mode == 0
. Y dejará solo bits interesantes, XOR comprobará qué bits están configurados. La== 0
comparación explícita es más significativa quebool()
.setWindowFlags
. Ejemplo:setWindowFlags(SplashScreen | WindowStaysOnTopHint)
. Todavía lo encuentro confuso, ya que parece un interruptor que está configurando en 'activado', por lo que parece más intuitivo para 'y' en tal caso.Las representaciones de bits de enteros se utilizan a menudo en la informática científica para representar matrices de información verdadero-falso porque una operación bit a bit es mucho más rápida que iterar a través de una matriz de valores booleanos. (Los lenguajes de nivel superior pueden usar la idea de una matriz de bits).
Un ejemplo bonito y bastante simple de esto es la solución general al juego de Nim. Eche un vistazo al código Python en la página de Wikipedia . Se hace un uso intensivo de exclusiva bit a bit o,
^
.fuente
Puede haber una mejor manera de encontrar dónde está un elemento de matriz entre dos valores, pero como muestra este ejemplo, el & funciona aquí, mientras que y no.
fuente
No vi que se mencionara. Este ejemplo le mostrará la operación decimal (-) para valores de 2 bits: AB (solo si A contiene B)
esta operación es necesaria cuando tenemos un verbo en nuestro programa que representa bits. a veces necesitamos agregar bits (como arriba) y a veces necesitamos eliminar bits (si el verbo contiene entonces)
con python: 7 & ~ 4 = 3 (elimine de 7 los bits que representan 4)
con python: 1 & ~ 4 = 1 (elimine de 1 los bits que representan 4 - en este caso 1 no es 'contiene' 4) ..
fuente
Si bien la manipulación de bits de un número entero es útil, a menudo para protocolos de red, que se pueden especificar hasta el bit, se puede requerir la manipulación de secuencias de bytes más largas (que no se convierten fácilmente en un número entero). En este caso, es útil emplear la biblioteca de cadenas de bits que permite operaciones bit a bit en datos; por ejemplo, se puede importar la cadena 'ABCDEFGHIJKLMNOPQ' como una cadena o como hexadecimal y bit shift (o realizar otras operaciones bit a bit):
fuente
los siguientes operadores bit a bit: & , | , ^ y ~ devuelven valores (basados en su entrada) de la misma manera que las puertas lógicas afectan las señales. Podrías usarlos para emular circuitos.
fuente
Para invertir bits (es decir, complemento / inversión de 1) puede hacer lo siguiente:
Dado que el valor ExORed con todos los 1 resulta en inversión, para un ancho de bit dado puede usar ExOR para invertirlos.
fuente