python - operator - Operación a nivel de bit y uso
python and operator (15)
Considera 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 en otros lenguajes), pero nunca entendí bastante bien a 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.
¿Para qué se usan realmente los operadores bit a bit? Agradecería algunos ejemplos.
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.
def hexToRgb(value):
# Convert string to hexadecimal number (base 16)
num = (int(value.lstrip("#"), 16))
# Shift 16 bits to the right, and then binary AND to obtain 8 bits representing red
r = ((num >> 16) & 0xFF)
# Shift 8 bits to the right, and then binary AND to obtain 8 bits representing green
g = ((num >> 8) & 0xFF)
# Simply binary AND to obtain 8 bits representing blue
b = (num & 0xFF)
return (r, g, b)
Sé que hay formas más eficientes de lograr esto, pero creo que este es un ejemplo muy conciso que ilustra tanto los cambios como las operaciones booleanas a nivel de bit.
Conjuntos
Los conjuntos se pueden combinar usando operaciones matemáticas.
- El operador sindical
|
combina dos conjuntos para formar uno nuevo que contiene elementos en cualquiera de ellos. - El operador de intersección
&
obtiene elementos solo en ambos. - El operador de diferencia
-
obtiene elementos en el primer conjunto, pero no en el segundo. - El operador de diferencia simétrica
^
obtiene elementos en cualquier conjunto, pero no en ambos.
Inténtalo tú mismo:
first = {1, 2, 3, 4, 5, 6}
second = {4, 5, 6, 7, 8, 9}
print(first | second)
print(first & second)
print(first - second)
print(second - first)
print(first ^ second)
Resultado:
{1, 2, 3, 4, 5, 6, 7, 8, 9}
{4, 5, 6}
{1, 2, 3}
{8, 9, 7}
{1, 2, 3, 7, 8, 9}
Creo que la segunda parte de la pregunta:
Además, ¿para qué se utilizan realmente los operadores bit a bit? Agradecería algunos ejemplos.
Ha sido solo parcialmente abordado. Estos son mis dos centavos en ese asunto.
Las operaciones a nivel de bit en los lenguajes de programación desempeñan un papel fundamental cuando se trata de muchas aplicaciones. Casi toda la informática de bajo nivel se debe hacer utilizando este tipo de operaciones.
En todas las aplicaciones que necesitan enviar datos entre dos nodos, como por ejemplo:
Red de computadoras;
aplicaciones de telecomunicaciones (teléfonos celulares, comunicaciones por satélite, etc.).
En la capa de comunicación de nivel inferior, los datos generalmente se envían en lo que se llama marcos . Los marcos son cadenas de bytes que se envían a través de un canal físico. Estos marcos suelen contener los datos reales más algunos otros campos (codificados en bytes) que forman parte de lo que se llama el encabezado . El encabezado generalmente contiene bytes que codifican cierta información relacionada con el estado de la comunicación (por ejemplo, con indicadores (bits)), contadores de cuadros, códigos de corrección y detección de errores, etc. Para obtener los datos transmitidos en un marco, y construir el marcos para enviar datos, necesitará operaciones de bit a bit seguras.
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 no es necesario que construya los marcos de comunicación TCP / IP. Pero piense en las buenas personas que programaron esas API para usted, seguramente tuvieron que lidiar con la construcción de marcos; utilizando todo tipo de operaciones bit a bit para ir y venir desde la comunicación de bajo nivel a la de mayor nivel.
Como ejemplo concreto, imagine que alguien le proporciona un archivo que contiene datos sin procesar que fueron capturados directamente por el hardware de telecomunicaciones. En este caso, para encontrar los marcos, necesitará leer los bytes sin formato en el archivo e intentar encontrar algún tipo de palabras de sincronización, escaneando los datos poco a poco. Después de identificar las palabras de sincronización, necesitará obtener los cuadros reales, y CAMBIARlos si es necesario (y eso 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 hardware utilizando algunos puertos (antiguos), como puertos serie y paralelo. Estos puertos se controlan configurando algunos bytes, y cada bit de esos bytes tiene un significado específico, en términos de instrucciones, para ese puerto (ver por ejemplo http://en.wikipedia.org/wiki/Parallel_port ). Si desea construir un software que haga algo con ese hardware, necesitará operaciones a nivel de 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 de software:
read = ((read ^ 0x80) >> 4) & 0x0f;
Espero que esto contribuya.
Espero que esto aclare esos dos:
x | 2
0001 //x
0010 //2
0011 //result = 3
x & 1
0001 //x
0001 //1
0001 //result = 1
Este ejemplo le mostrará las operaciones para los cuatro valores de 2 bits:
10 | 12
1010 #decimal 10
1100 #decimal 12
1110 #result = 14
10 & 12
1010 #decimal 10
1100 #decimal 12
1000 #result = 8
Aquí hay un ejemplo de uso:
x = raw_input(''Enter a number:'')
print ''x is %s.'' % (''even'', ''odd'')[x&1]
Las representaciones de bits de los enteros se utilizan a menudo en la informática científica para representar matrices de información verdadera-falsa porque una operación a nivel de bit es mucho más rápida que iterar a través de una matriz de booleanos. (Los lenguajes de nivel superior pueden usar la idea de una matriz de bits).
Un buen y bastante simple ejemplo de esto es la solución general al juego de Nim. Eche un vistazo al código de Python en la página de Wikipedia . Hace un uso intensivo de bitwise exclusive o, ^
.
Los operadores bit a bit son operadores que trabajan en valores de varios bits, pero conceptualmente bit por bit.
-
AND
es 1 solo si sus dos entradas son 1, de lo contrario es 0. -
OR
es 1 si una o ambas de sus 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.
Estos a menudo se pueden mostrar 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.
AND | 0 1 OR | 0 1 XOR | 0 1 NOT | 0 1
----+----- ---+---- ----+---- ----+----
0 | 0 0 0 | 0 1 0 | 0 1 | 1 0
1 | 0 1 1 | 1 1 1 | 1 0
Un ejemplo es si solo desea los 4 bits más bajos de un entero, usted Y con 15 (1111 binarios) entonces:
201: 1100 1001
AND 15: 0000 1111
------------------
IS 9 0000 1001
Los bits cero en 15 en ese caso actúan efectivamente como un filtro, forzando a los bits en el resultado a ser cero también.
Además, >>
y <<
menudo se incluyen como operadores bit a bit, y "cambian" un valor respectivamente a la derecha y a la izquierda por un cierto número de bits, tirando los bits que giran hacia el final hacia el que se está desplazando, y alimentando Cero bits en el otro extremo.
Así por ejemplo:
1001 0101 >> 2 gives 0010 0101
1111 1111 << 4 gives 1111 0000
Tenga en cuenta que el desplazamiento a la izquierda en Python es inusual, ya que no utiliza un ancho fijo donde los bits se descartan, mientras que muchos idiomas usan un ancho fijo basado en el tipo de datos, Python simplemente expande el ancho para abastecer bits adicionales. Para obtener el comportamiento de descarte en Python, puede seguir un desplazamiento a la izquierda con un bit and
tal como en un valor de 8 bits desplazando a la izquierda cuatro bits:
bits8 = (bits8 << 4) & 255
Con esto en mente, otro ejemplo de operadores bit a bit es que si tiene dos valores de 4 bits que desea empacar en uno de 8 bits, puede usar los tres operadores ( left-shift
, and
y or
):
packed_val = ((val1 & 15) << 4) | (val2 & 15)
- La operación
& 15
se asegurará de que ambos valores solo tengan los 4 bits más bajos. - El
<< 4
es un desplazamiento de 4 bits para moverval1
a los 4 bits superiores de un valor de 8 bits. - El
|
simplemente combina estos dos juntos.
Si val1
es 7 y val2
es 4:
val1 val2
==== ====
& 15 (and) xxxx-0111 xxxx-0100 & 15
<< 4 (left) 0111-0000 |
| |
+-------+-------+
|
| (or) 0111-0100
No lo he visto antes, pero también verá que algunas personas usan el desplazamiento a la izquierda y a la derecha para las operaciones aritméticas. Un desplazamiento a la izquierda en x es equivalente 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 usando x << 1 yx >> 1 para doblar y dividir a la mitad, aunque no estoy seguro de si solo están tratando de ser inteligentes o si realmente hay una clara ventaja sobre los operadores normales.
No lo he visto mencionado. 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 algunas veces necesitamos quitar bits (si el verbo contiene)
111 #decimal 7
-
100 #decimal 4
--------------
011 #decimal 3
con python: 7 y ~ 4 = 3 (eliminar de 7 los bits que representan 4)
001 #decimal 1
-
100 #decimal 4
--------------
001 #decimal 1
con python: 1 & ~ 4 = 1 (eliminar de 1 los bits que representan 4 - en este caso 1 no es ''contiene'' 4) ..
Otro caso de uso común es manipular / probar permisos de archivos. Ver 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, podría hacer algo como:
import os
import stat
#Get the actual mode of a file
mode = os.stat(''file.txt'').st_mode
#File should be a regular file, readable and writable by its owner
#Each permission value has a single ''on'' bit. Use bitwise or to combine
#them.
desired_mode = stat.S_IFREG|stat.S_IRUSR|stat.S_IWUSR
#check for exact match:
mode == desired_mode
#check for at least one bit matching:
bool(mode & desired_mode)
#check for at least one bit ''on'' in one, and not in the other:
bool(mode ^ desired_mode)
#check that all bits from desired_mode are set in mode, but I don''t care about
# other bits.
not bool((mode^desired_mode)&desired_mode)
Eché los resultados como booleanos, porque solo me importa la verdad o la falsedad, pero sería un ejercicio útil imprimir los valores de bin () para cada uno.
Piense en 0 como falso y 1 como verdadero. Luego, en modo bit y (&) y o (|) funcionan igual que regular y y o excepto que hacen todos los bits en el valor a la vez. Por lo general, los verá utilizados para banderas si tiene 30 opciones que se pueden establecer (por ejemplo, como dibujar estilos en una ventana) no desea tener que pasar en 30 valores booleanos separados para establecer o deshacer cada uno de manera que use | para combinar opciones en un solo valor y luego usa & para verificar si cada opción está configurada. Este estilo de aprobación de banderas es muy utilizado por OpenGL. Como cada bit es una marca separada, obtienes valores de indicador en potencias de dos (también conocidos como números que tienen un solo bit) 1 (2 ^ 0) 2 (2 ^ 1) 4 (2 ^ 2) 8 (2 ^ 3) la potencia de dos le indica qué bit se establece si la bandera está activada.
También note 2 = 10 entonces 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.
Puede haber una mejor manera de encontrar dónde se encuentra un elemento de matriz entre dos valores, pero como muestra este ejemplo, el & funciona aquí, mientras que y no.
import numpy as np
a=np.array([1.2, 2.3, 3.4])
np.where((a>2) and (a<3))
#Result: Value Error
np.where((a>2) & (a<3))
#Result: (array([1]),)
Si bien la manipulación de bits de un entero es útil, a menudo para protocolos de red, que pueden especificarse hasta el bit, se puede requerir la manipulación de secuencias de bytes más largos (que no se convierten fácilmente en un entero). En este caso, es útil emplear la biblioteca de bitstring de bits que permite operaciones bit a bit en los datos; por ejemplo, se puede importar la cadena ''ABCDEFGHIJKLMNOPQ'' como una cadena o como hex y desplazarla en bits (o realizar otras operaciones bit a bit):
>>> import bitstring
>>> bitstring.BitArray(bytes=''ABCDEFGHIJKLMNOPQ'') << 4
BitArray(''0x142434445464748494a4b4c4d4e4f50510'')
>>> bitstring.BitArray(hex=''0x4142434445464748494a4b4c4d4e4f5051'') << 4
BitArray(''0x142434445464748494a4b4c4d4e4f50510'')
Un uso típico:
|
se usa para establecer un cierto bit a 1
&
se usa para probar o borrar un cierto bit
Establezca un bit (donde n es el número de bit, y 0 es el bit menos significativo):
unsigned char a |= (1 << n);
Limpia 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
x | 2
se usa para configurar el bit 1 de x
en 1
x & 1
se usa para probar si el bit 0 de x
es 1 o 0
los siguientes operadores bit a bit: &, | y ^ funcionan como compuertas lógicas . Puedes usarlos para emular circuitos.