¿Cómo funciona la operación bit a bit en Booleanos?

26

Encontré este desafío en Edabit y no pude resolver esta solución de operación bit a bit.

notNotNot = (a,b) => !!(a%2 >> b)

El reto:

//Something which is not true is false, but something which is not not true is true! 
//Create a function where given n number of "not", evaluate whether it's true or false.

//Examples:
notNotNot(1, true)  false
// Not true

notNotNot(2, false)  false
// Not not false

notNotNot(6, true)  true
// Not not not not not not true

Investigué un poco que ese operador:

Se desplaza hacia la derecha empujando copias del bit más a la izquierda desde la izquierda, y deja que los bits más a la derecha se caigan.

Creo que entendí (por ejemplo, lo 5 >> 1mismo 0101 >> 1que evalúa 0010), pero no puedo ver cómo funciona eso con un booleano. Sé que trueevalúa a 1y falsea 0.

kiabbott
fuente
3
Un booleano simplemente se transformará en un número y luego se producirá el cambio, por lo que true= 1(decimal) = 01(binario) desplazado a la izquierda por uno produciría 10binario o 2decimal.
VLAZ
En realidad, esta solución es incorrecta. En los casos mencionados anteriormente funcionará, pero considere notNotNot(2, true): volverá false, pero no es cierto ( !!true) debería ser true...
FZs
@FZs eso es correcto. La función solo considerará un número impar de nots en una falseresolución true.
VLAZ
2
Yo diría en notNotNot = (a,b) => !!((a%2)^b)cambio ...
FZs
¿Por qué no solo (a, b) => !!((a + b) % 2)?
Jonas Wilms

Respuestas:

16

La función que le diste no satisface el desafío. El desplazamiento correcto no hará lo que se le pide. Por ejemplo, su notNotNot(6,true)es false, no truecuando pasa a través de su función.

Sin embargo, su pregunta es sobre la operación bit a bit en un booleano. Como a los operadores les gusta >>y <<trabajan con enteros, Javascript primero convierte el valor booleano en un entero. Entonces se trueconvierte en 1 y se falseconvierte en 0. Para ver esto, puede cambiar por cero:

console.log("true is",true >> 0)
console.log("false is", false >> 0)
Entonces, la operación bit a bit en booleanos es realmente una operación bit a bit en 0 o 1.

Usar !!es una forma práctica de convertir cualquier cosa en un booleano. Se necesita cualquier cosa que se considere equivalente a falso (como 0 null, undefinedo "") y se devuelve false. Del mismo modo, todo lo que sea verdadero (como 14, "hola", [4], {a: 1}) y devolver true. !!funciona porque el primer signo de exclamación da el 'no' de la expresión que siempre es trueo false, luego el segundo signo de exclamación da lo contrario de eso ( falseo true).

Volviendo al desafío, quiere aplicar el no operador 'a' veces y compararlo con el valor 'b'. Entonces algo como esto funcionaría:

function notNotNot(a, b) { return !!(a%2 - b); }
console.log("notNotNot(1, true)",notNotNot(1, true));
console.log("notNotNot(2, false)",notNotNot(2, false));
console.log("notNotNot(6, true)",notNotNot(6, true));

Siempre aprendiendo
fuente
99
Creo que el "desafío" realmente quiere que te
des
2
@ BlueRaja-DannyPflughoeft de hecho. La forma más sencilla de hacerlo sin un bucle es, if (a % 2 === 1) return !b else return bpero allí, como se muestra en otras respuestas, hay maneras de hacerlo sin ramificaciones ni bucles.
VLAZ
sí, pero la pregunta no era sobre hacer el desafío, sino sobre cómo el operador bit a bit y los valores booleanos. Pero he actualizado mi respuesta con un modo sin bucle y sin if.
Siempre aprendiendo el
14

Los operadores bit a bit siempre convierten sus operandos a un número entero. Entonces, 4 >> truees lo mismo 4 >> 1que hará un poco de cambio en una posición

(decimal) 4 = (binary) 100

(binary) 100 >> 1 = (binary) 010

(binary) 010 = (decimal) 2

console.log(4 >> true);

Entonces, usar trueo falsees solo una forma indirecta de usar 1o 0.

La notNotNotfunción tiene una operación muy simple, en general:

  1. a%2convierte el primer número en 0par o 1impar.
  2. >> bdesplaza a la derecha por 0posiciones para falseo 1posición para true.
    • aes impar (1) y bes false=1
      • hay cero desplazamientos a la derecha, por lo que el número sigue siendo el mismo.
    • aes impar (1) y bes true=0
      • el único bit establecido 1se desplaza hacia la derecha y se descarta.
    • aes par (0) y bes false=0
      • hay cero desplazamientos a la derecha, por lo que el número sigue siendo el mismo.
    • aes par (0) y bes true=0
      • el número base es el 0que no tiene ningún bit establecido, por lo que desplazar a la derecha cualquier cantidad no lo cambia.
  3. !!() convierte el resultado a booleano.

Dicho esto, la solución aquí es incorrecta, ya notNotNot(2, true)que producirá false, aes uniforme y bes true. La expectativa es que producirá truedesde entonces !!true = true. El mismo problema está presente para cualquier número par y true.

Se puede arreglar fácilmente usando XOR bit a bit en lugar del desplazamiento a la derecha:

  • aes impar (1) y bes false=1
    • ambos coinciden, por lo que se cambian a 0
  • aes impar (1) y bes true=0
    • no coinciden, así que obtenemos 1
  • aes par (0) y bes false=0
    • ambos coinciden, así que obtenemos 0
  • aes par (0) y bes true=1
    • no coinciden, así que obtenemos 1

notNotNot = (a,b) => !!(a%2 ^ b);

console.log("!!true = ", notNotNot(2, true))
console.log("!!!true =", notNotNot(3, true))
console.log("!!false = ", notNotNot(2, false))
console.log("!!!false = ", notNotNot(3, false))

//bonus
console.log("true = ", notNotNot(0, true))
console.log("false = ", notNotNot(0, false))

Solo por completo, en caso de que desee una operación totalmente bit a bit:

La operación del módulo %2se puede cambiar a bit a bit Y &1obtener el bit más bajo. Para números pares, esto produciría 0ya que estarías calculando

xxx0
&
0001

que es cero Y para números impares se aplica lo mismo, pero como resultado obtendría uno:

xxx1
&
0001

Entonces los resultados de a&1y a%2son idénticos. Además, a pesar de que las operaciones bit a bit convierten el número a un entero con signo de 32 bits que no importa, ya que se preservaría la paridad .

VLAZ
fuente
4

En primer lugar, (a,b) => !!(a%2 >> b)no coincide con los resultados de los ejemplos. Desglosaré exactamente lo que está haciendo usando notNotNot(6, true) ➞ true.

  • Puño a%2, simplemente adivide entre 2 y devuelve el resto. Entonces obtendremos 0 para un número par y 1 para un número impar. a = 6 a%2 = 0en este caso.
  • Luego 0 >> bdesplace 1 número desde la derecha porque, como dijo, se trueevalúa como 1. Entonces lo conseguimos 0 >> 1 = 0.
  • Por último !!(0), es simple y puede desglosarse así !0 = true, entonces !true = false.

Así que si pensamos en esto el tiempo que bes true, que siempre llegan regresamos false. Digamos que tenemos a = 5, b = true evaluar a 5%2 = 1, 1 >> 1 = 0. Puede ver que debido al mod ( %2) solo tendremos 1 o 0 (solo tendremos 1 dígito) y verdadero siempre se desviará del 1 cuando lo tengamos.

Una manera simple de ver este problema es como una isEvenOrNotfunción. Entonces, aes el número que estamos verificando y bes un valor booleano para verificar si es par (verdadero) o incluso par (falso). Esto funciona porque cada segundo notagregado será cierto.

Por lo tanto el uso de una solución a nivel de bits podría ser algo como: (a,b) => !!(a&1 ^ b). ¡Te dejaré divertirte al analizar por qué funciona! :)

Un poco más para explicar cómo funciona shift con un booleano. Entonces, truecomo dijiste, será 1 y falso será 0. Entonces, como se muestra en tu ejemplo, 0101 >> truees lo mismo que 0101 >> 1.

Espero que esto ayude.

Usé lo siguiente como referencia para bitwise: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators

domsim1
fuente
1
(a%2)  //ignore all but the least significant bit (LSB)
(a%2 >> b )  //if TRUE,  shifts right, resolves to 0
               //if FALSE, no shift,     resolves to LSB

// 0 and LSB are both integers so convert to boolean by using logical/boolean NOT
!(a%2 >> b ) //resolves to the boolean which it is NOT
!!(a%2 >> b ) //resolves to the boolean which it is NOT NOT

Nota: para cualquier booleano, un número par de NOT da como resultado el booleano original y un número impar de NOT da como resultado el booleano opuesto

El LSB de cualquier número dicta si el número es impar o par. (0 par, 1 impar)

Stephen Duffy
fuente
1

Veo que tu tarea es:

/* Create a function where given n number of "not",
   evaluate whether it's true or false.*/

No sé por qué estás escribiendo una notnotnotfunción para mí que no es lo que pide la tarea.

Entonces, de acuerdo con la tarea, hice esa función not que acepta una serie de "nots" y los evalúa.

La primera forma

function not(n) {
  return Boolean(n - n - 1);
}

La segunda forma usando XOr (^)

function not(n) {
  return Boolean(bool ^ (bool - 1));
}

La tercera forma usando Mod (%) señalado por @VLAZ

function not(n) {
  return Boolean(n % 2);
}

La cuarta forma usando bitwise Y (&)

function not(n) {
  return Boolean(n & 1);
}

Prueba

not(0)
//> false 
not(1)
//> true
not(2)
//> false
not(515)
//> true
SaymoinSam
fuente
1
La manipulación de bits es útil aquí, ya que no nos importa la cantidad n, solo si es par o impar, ya que cualquiera de los dos NOT se cancela, por lo que !!!!!bes lo mismo !b. Por lo tanto, no necesitamos un bucle si solo tomamos n%2: obtendríamos 1NOT y 0para "mantenerlo igual". Como tenemos un número, solo podemos hacer operaciones bit a bit.
VLAZ
Bueno, no pensé en eso, pero tienes razón, solo estamos tratando con 0 y 1, gracias, este es un comentario útil :)
SaymoinSam
0

Deja la solución de análisis primero

notNotNot(oddNumber, true)   false
notNotNot(evenNumber, true)  true

notNotNot(oddNumber, false)   true
notNotNot(evenNumber, false)  false

Ahora analice el para (a,b) => !!(a%2 >> b)

a%2 == 0  even number
a%2 == 1  odd number

// For a%2 == 0

a%2 >> b  if b is true   0 >> 1  0   // Not working
a%2 >> b  if b is false  0 >> 0  0


// For a%2 == 1

a%2 >> b  if b is true   1 >> 1  0
a%2 >> b  if b is false  1 >> 0  1

Thats medios esto no está funcionando para notNotNot(6, true)es true, pero da solución actual false.

Podemos usted ^(XOR) operador para que sea correcto Me gusta(a,b) => !!(a%2 ^ b)

Ahora analice el para (a,b) => !!(a%2 ^ b)

a%2 == 0  even number
a%2 == 1  odd number

// For a%2 == 0

a%2 ^ b  if b is true   0 ^ 1  1   // Now working
a%2 ^ b  if b is false  0 ^ 0  0


// For a%2 == 1

a%2 ^ b  if b is true   1 ^ 1  0
a%2 ^ b  if b is false  1 ^ 0  1

!(a%2 ^ b) use `!` to make int as boolean but solution result will reversed then
!!(a%2 ^ b) use `!` again to reversed it again and make it correct.

Ejemplo:

notNotNot = (a,b) => !!(a%2 ^ b);

console.log("!!!!true = ", notNotNot(4, true))
console.log("!!!!false = ", notNotNot(4, false))
console.log("!!!true =", notNotNot(3, true))
console.log("!!!false = ", notNotNot(3, false))

Eklavya
fuente