Comment fonctionne l'opération au niveau du bit sur les booléens?

26

J'ai rencontré ce défi sur Edabit et je n'ai pas pu trouver cette solution d'opération au niveau du bit.

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

Le défi:

//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

J'ai fait des recherches sur cet opérateur:

Décale vers la droite en poussant des copies du bit le plus à gauche à partir de la gauche et laisse tomber les bits le plus à droite.

Que je pense avoir compris (par exemple, le 5 >> 1même que celui 0101 >> 1qui évalue 0010), mais je ne vois pas comment cela fonctionne avec un booléen? Je sais trueévalue vers 1et falsevers 0.

kiabbott
la source
3
Un booléen va juste être transformé en nombre, puis le décalage se produira, donc true= 1(décimal) = 01(binaire) décalé de gauche de un produirait du 10binaire ou du 2décimal.
VLAZ
En fait, cette solution est incorrecte. Dans les cas susmentionnés, cela fonctionnera, mais considérez notNotNot(2, true): cela reviendra false, mais ce n'est pas vrai ( !!true) devrait être true...
FZs
@FZs c'est correct. La fonction ne considérera qu'un nombre impair de nots sur lesquels falsese résoudre true.
VLAZ
2
Je dirais notNotNot = (a,b) => !!((a%2)^b)plutôt ...
FZs
Pourquoi pas juste (a, b) => !!((a + b) % 2)?
Jonas Wilms

Réponses:

16

La fonction que vous avez donnée ne répond pas au défi. Le décalage à droite ne fera pas ce qui est demandé. Par exemple, votre notNotNot(6,true)est false, pastrue lorsque vous exécutez votre fonction.

Votre question concerne le fonctionnement au niveau du bit sur un booléen. Puisque les opérateurs aiment >>et <<travaillent sur des entiers, Javascript convertit d'abord la valeur booléenne en un entier. Devient donc true1 et falsedevient 0. Pour voir cela, vous pouvez décaler de zéro:

console.log("true is",true >> 0)
console.log("false is", false >> 0)
Donc, l'opération au niveau du bit sur les booléens est vraiment juste une opération au niveau du bit sur 0 ou 1.

L'utilisation !!est un moyen pratique de convertir n'importe quoi en booléen. Il prend tout ce qui serait considéré comme équivalent à faux (comme 0 null, undefinedou "") et redonne false. De même, tout ce qui est véridique (comme 14, "bonjour", [4], {a: 1}) et redonner true. !!fonctionne parce que le premier point d'exclamation donne le «non» de l'expression qui est toujours trueou false, alors le deuxième point d'exclamation donne l'opposé de celui ( falseou true).

Pour en revenir au défi, il veut appliquer les temps non-opérateur «a» et comparer à la valeur «b». Donc, quelque chose comme ça fonctionnerait:

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));

Toujours entrain d'apprendre
la source
9
Je pense que le "défi" veut vraiment que vous réalisiez que vous pouvez facilement le faire sans boucle ...
BlueRaja - Danny Pflughoeft
2
@ BlueRaja-DannyPflughoeft en effet. Le moyen le plus simple de le faire sans boucle est, if (a % 2 === 1) return !b else return bmais comme indiqué dans d'autres réponses, il existe des moyens de le faire sans branchement ni boucle.
VLAZ
oui, mais la question n'était pas de relever le défi - il s'agissait de savoir comment l'opérateur au niveau du bit et les valeurs booléennes. Mais j'ai mis à jour ma réponse avec une méthode sans boucle et sans if.
Toujours en apprentissage le
14

Les opérateurs au niveau du bit convertissent toujours leurs opérandes en un entier. Donc, 4 >> truec'est la même chose que celle 4 >> 1qui fera un peu de décalage vers la droite d'une position

(decimal) 4 = (binary) 100

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

(binary) 010 = (decimal) 2

console.log(4 >> true);

Donc, utiliser trueou falsen'est qu'un moyen détourné d'utiliser 1ou 0.

La notNotNotfonction a un fonctionnement très simple, dans l'ensemble:

  1. a%2convertit le premier nombre en 0pair ou 1en impair.
  2. >> bdécale vers la droite par des 0positions pour falseou une 1position pourtrue .
    • aest impair (1) et best false=1
      • il n'y a aucun décalage vers la droite, donc le nombre reste le même.
    • aest impair (1) et best true=0
      • le seul bit défini 1est décalé vers la droite et rejeté.
    • aest pair (0) et best false=0
      • il n'y a aucun décalage vers la droite, donc le nombre reste le même.
    • aest pair (0) et best true=0
      • le numéro de base est celui 0qui n'a pas de bits, donc le décalage vers la droite ne change rien.
  3. !!() convertit le résultat en booléen.

Cela dit, la solution ici est fausse, car notNotNot(2, true)produira false- aest pair et best true. On s'attend à ce qu'il produise truedepuis !!true = true. Le même problème est présent pour tout nombre pair et true.

Il peut être facilement corrigé en utilisant XOR au niveau du bit au lieu du décalage vers la droite:

  • aest impair (1) et best false=1
    • les deux correspondent, ils sont donc retournés à 0
  • aest impair (1) et best true=0
    • ils ne correspondent pas, donc nous obtenons 1
  • aest pair (0) et best false=0
    • les deux correspondent, donc nous obtenons 0
  • aest pair (0) et best true=1
    • ils ne correspondent pas, donc nous obtenons 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))

Par souci d'exhaustivité, au cas où vous souhaiteriez une opération entièrement au niveau du bit:

L'opération modulo %2peut être changée en bit à bit ET &1obtenir le bit le plus bas. Pour les nombres pairs, cela donnerait 0puisque vous calculeriez

xxx0
&
0001

ce qui est nul. Et pour les nombres impairs, la même chose s'applique, mais vous en obtiendriez un en conséquence:

xxx1
&
0001

Les résultats de a&1et a%2sont donc identiques. De plus, même si les opérations au niveau du bit convertissent le nombre en un entier signé 32 bits, cela n'a pas d'importance car la parité serait préservée.

VLAZ
la source
4

Premièrement, (a,b) => !!(a%2 >> b)ne correspond pas aux résultats des exemples. Je décomposerai exactement ce qu'il fait en utilisant notNotNot(6, true) ➞ true.

  • Poing a%2, obtenez simplementa diviser par 2 pour retourner le reste. Nous obtiendrons donc 0 pour un nombre pair et 1 pour un nombre impair.a = 6 a%2 = 0dans ce cas.
  • Ensuite , 0 >> bpasser 1 numéro hors du droit parce que vous avez dit trueevalue à1 . Donc, nous obtenons 0 >> 1 = 0.
  • Enfin !!(0), est simple et peut être décomposé comme tel !0 = true, alors!true = false .

Donc , si nous pensons à ce aussi longtemps que best true, nous seront toujours retournés false. Disons que nous avons a = 5, b = true 5%2 = 1,1 >> 1 = 0 . Vous pouvez voir à cause du mod ( %2) que nous n'aurons que 1 ou 0 (seulement 1 chiffre) et true décalera toujours le 1 lorsque nous l'aurons.

Une façon simple de voir ce problème est comme une isEvenOrNotfonction. Tout acomme le nombre que nous vérifions etb vérifions est un booléen pour vérifier s'il est pair (vrai) ou pas (faux). Cela fonctionne car chaque seconde notajoutée sera vraie.

Ainsi , une solution à l' aide pourrait être quelque chose bitwise comme: (a,b) => !!(a&1 ^ b). Je vous laisse vous amuser à expliquer pourquoi cela fonctionne! :)

Un peu plus pour expliquer comment fonctionne shift avec un booléen. Donc, truecomme vous l'avez dit, ce sera 1 et false sera 0. Ainsi, comme le montre votre exemple, 0101 >> truec'est la même chose que 0101 >> 1.

J'espère que ça aide.

J'ai utilisé ce qui suit comme référence pour bitwise: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators

domsim1
la source
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

NB Pour chaque booléen, un nombre pair de NOTs donne le booléen d'origine et un nombre impair de NOTs donne le booléen opposé

Le LSB de n'importe quel nombre dicte si le nombre est pair ou impair. (0 pair, 1 impair)

Stephen Duffy
la source
1

Je vois que votre tâche est:

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

Je ne sais pas pourquoi vous écrivez une notnotnotfonction pour moi, ce n'est pas ce que la tâche demande.

Donc, selon la tâche que j'ai faite cette fonction not qui accepte un certain nombre de «non» et les évalue.

La première façon

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

La deuxième façon d'utiliser XOr (^)

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

La troisième façon d'utiliser Mod (%) pointée par @VLAZ

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

La quatrième façon d'utiliser And au niveau du bit (&)

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

Tester

not(0)
//> false 
not(1)
//> true
not(2)
//> false
not(515)
//> true
SaymoinSam
la source
1
La manipulation des bits est utile ici, car nous ne nous soucions pas du montant n- seulement s'il est pair ou impair, puisque deux NOTs s'annulent, !!!!!bc'est la même chose que !b. Par conséquent, nous n'avons pas besoin d'une boucle si nous prenons simplement n%2- nous obtiendrions 1pour NOT et 0pour "garder la même chose". Puisque nous avons un nombre, nous pouvons simplement effectuer des opérations au niveau du bit.
VLAZ
Eh bien, je n'y ai pas pensé, mais vous avez raison, nous n'avons affaire qu'à 0 et 1, merci, c'est un commentaire utile :)
SaymoinSam
0

Permet d'abord une solution d'analyse

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

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

Maintenant, analyse le pour (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

Des moyens de Thats cela ne fonctionne pas pour notNotNot(6, true)est , truemais la solution actuelle donne false.

Nous pouvons vous ^(XOR) opérateur pour le rendre correct(a,b) => !!(a%2 ^ b)

Maintenant, analyse le pour (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.

Exemple:

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
la source