Operadores booleanos vs operadores bitwise

Estoy confundido en cuanto a cuándo debo usar los operadores Boolean vs Bitwise

and vs &, or vs | 

¿Podría alguien aclararme cuándo debo usar cada uno y cuándo el usar uno sobre el otro afectará mis resultados?

Aquí hay un par de pautas:

  • Los operadores booleanos se usan generalmente en valores booleanos , pero los operadores a nivel de bits se usan en valores enteros .
  • Los operadores booleanos están en cortocircuito, pero los operadores a nivel de bits no son cortocircuitos.

El comportamiento de cortocircuito es útil en expresiones como esta:

 if x is not None and x.foo == 42: # ... 

Esto no funcionaría correctamente con el operador bitwise & porque ambos lados siempre se evaluarían, dando a AttributeError: 'NoneType' object has no attribute 'foo' . Cuando se utiliza el operador booleano and la segunda expresión no se evalúa cuando la primera es Falso. Similarmente or no evalúa el segundo argumento si el primero es Verdadero.

En teoría, and y or vienen directamente de la lógica booleana (y por lo tanto operan en dos booleanos para producir un booleano), mientras que y | aplicar los bits booleanos y / o a los bits individuales de enteros. Hay muchas preguntas aquí sobre cómo funcionan estas últimas exactamente.

Aquí hay diferencias prácticas que potencialmente pueden afectar sus resultados:

  1. and y or el cortocircuito, es decir, True or sys.exit(1) no se cerrará, porque para un cierto valor ( True or ... , False and ... ) del primer operando, el segundo no cambiaría el resultado = no necesita ser evaluado Pero | y & no cortocircuito – True | sys.exit(1) True | sys.exit(1) te echa fuera del REPL.
  2. (Solo se aplica a algunos idiomas con sobrecarga de operadores, incluido Python 🙂 & and | son operadores regulares y se pueden sobrecargar and se forjan en el idioma (aunque al menos en Python, el método especial de coerción a booleano puede tener efectos secundarios).
  3. (solo se aplica a unos pocos idiomas [ver el comentario de KennyTM] 🙂 and y or (siempre? nunca entiendo esto realmente, ni lo necesité) el valor de un operando en lugar de True o False . Esto no cambia el significado de las expresiones booleanas en las condiciones: 1 or True es 1 , pero 1 es verdadero. Pero una vez se usó para emular un operador condicional ( cond ? true_val : false_val en syntax C, true_val if cond else false_val en Python desde hace unos años). Para & y | , el tipo de resultado depende de cómo los operandos sobrecargan los respectivos métodos especiales ( True & False es False , 99 & 7 es 3 , para los conjuntos es uniones / intersecciones …).

Pero incluso cuando, por ejemplo, a_boolean & another_boolean funcionen de manera idéntica, la solución correcta es usar and , simplemente porque and y or están asociados con la expresión y condición booleanas mientras que & y | soporte para twiddling poco.

Aquí hay una diferencia adicional, que me desconcertó por un tiempo justo ahora: porque & (y otros operadores bitwise) tienen una precedencia más alta que and (y otros operadores booleanos) las siguientes expresiones evalúan a diferentes valores:

 0 < 1 & 0 < 2 

versus

 0 < 1 and 0 < 2 

A saber, el primero arroja False ya que es equivalente a 0 < (1 & 0) < 2 , por lo tanto 0 < 0 < 2 , por lo tanto 0 < 0 and 0 < 2 .

Si está intentando realizar operaciones booleanas de elementos en numpy , la respuesta es algo diferente. Puedes usar & y | para operaciones booleanas a nivel de elementos, pero and y or devolverán un error de valor.

Para estar en el lado seguro, puede usar las funciones lógicas numpy .

 np.array([True, False, True]) | np.array([True, False, False]) # array([ True, False, True], dtype=bool) np.array([True, False, True]) or np.array([True, False, False]) # ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() np.logical_or(np.array([True, False, True]), np.array([True, False, False])) # array([ True, False, True], dtype=bool) 

Las operaciones booleanas son operaciones lógicas.

Las operaciones bitwise son operaciones en bits binarios.

Operaciones bitwise:

 >>> k = 1 >>> z = 3 >>> k & z 1 >>> k | z 3 

Las operaciones:

 And & 1 if both bits are 1, 0 otherwise Or | 1 if either bit is 1 Xor ^ 1 if the bits are different, 0 if they're the same Not ~ Flip each bit 

Algunos de los usos de las operaciones bitwise:

1) Ajuste y borrado de bits

Operaciones booleanas:

 >>> k = True >>> z = False >>> k & z # and False >>> k | z # or True >>> 

La pista está en el nombre:

  • Los operadores booleanos son para realizar operaciones lógicas (las pruebas de la verdad son comunes en la progtwigción y la lógica formal)
  • Los operadores bitwise son para “twiddling de bits” (manipulación de bits bajos en bytes y tipos de datos numéricos)

Si bien es posible y, a veces, deseable (generalmente por razones de eficiencia) realizar operaciones lógicas con operadores a nivel de bits, generalmente debe evitarlos para tales fines para evitar errores sutiles y efectos secundarios no deseados.

Si necesita manipular bits, entonces los operadores de bits se construyen a propósito. El libro divertido: Hackers Delight contiene algunos ejemplos geniales y realmente útiles de lo que se puede lograr con la manipulación de bits.

La regla general es usar el operador apropiado para los operandos existentes. Utilice operadores booleanos (lógicos) con operandos booleanos y operadores bitwise con operandos integrales (más anchos) (nota: False es equivalente a 0 , y True a 1 ). El único escenario “complicado” es aplicar operadores booleanos a operandos no booleanos.
Tomemos un ejemplo simple, como se describe en [SO]: Python – Diferencias entre ‘y’ y ‘&’ [duplicado] : 5 & 7 vs. 5 and 7 .

Para el bit a bit y ( & ), las cosas son bastante sencillas:

 5 = 0b101 7 = 0b111 ----------------- 5 & 7 = 0b101 = 5 

Para lo lógico y , esto es lo que indica [Python 3]: operaciones booleanas (el énfasis es mío):

(Tenga en cuenta que ni y ni o restringen el valor y el tipo que devuelven a Falso y Verdadero , sino que devuelven el último argumento evaluado .

Ejemplo :

 >>> 5 and 7 7 >>> 7 and 5 5 

Por supuesto, lo mismo se aplica para | vs. o .

Boolean ‘y’ vs. Bitwise ‘&’:

Pseudo-code / Python me ayudó a entender la diferencia entre estos:

 def boolAnd(A, B): # boolean 'and' returns either A or B if A == False: return A else: return B def bitwiseAnd(A , B): # binary representation (eg 9 is '1001', 1 is '0001', etc.) binA = binary(A) binB = binary(B) # perform boolean 'and' on each pair of binaries in (A, B) # then return the result: # equivalent to: return ''.join([x*y for (x,y) in zip(binA, binB)]) # assuming binA and binB are the same length result = [] for i in range(len(binA)): compar = boolAnd(binA[i], binB[i]) result.append(compar) # we want to return a string of 1s and 0s, not a list return ''.join(result)