Wie funktioniert die bitweise Operation bei Booleschen Werten?

26

Ich bin auf Edabit auf diese Herausforderung gestoßen und konnte diese bitweise Operationslösung nicht ausarbeiten.

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

Die Herausforderung:

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

Ich habe einige Nachforschungen angestellt, dass dieser Betreiber:

Verschiebt sich nach rechts, indem Kopien des am weitesten links liegenden Bits von links hineingeschoben werden und die am weitesten rechts liegenden Bits abfallen.

Das glaube ich verstanden zu haben (zB das 5 >> 1gleiche wie das, 0101 >> 1was ausgewertet wird 0010), aber ich kann nicht sehen, wie das mit einem Booleschen Wert funktioniert? Ich weiß, truebewertet zu 1und falsezu 0.

Kiabbott
quelle
3
Ein Boolescher Wert wird nur in eine Zahl umgewandelt, und dann tritt die Verschiebung auf, sodass true= 1(dezimal) = 01(binär), um eins nach links verschoben, 10binär oder 2dezimal erzeugt wird.
VLAZ
Eigentlich ist diese Lösung falsch. In den oben genannten Fällen wird es funktionieren, aber bedenken Sie notNotNot(2, true): Es wird zurückkehren false, aber nicht wahr ( !!true) sollte true...
FZs
@ FZs das ist richtig. Die Funktion berücksichtigt nur eine ungerade Anzahl von Nots auf einem falsezu auflösenden true.
VLAZ
2
Ich würde notNotNot = (a,b) => !!((a%2)^b)stattdessen sagen ...
FZs
Warum nicht einfach (a, b) => !!((a + b) % 2)?
Jonas Wilms

Antworten:

16

Die von Ihnen angegebene Funktion erfüllt die Herausforderung nicht. Rechtsverschiebung wird nicht das tun, was verlangt wird. Zum Beispiel Ihre notNotNot(6,true)heißt false, nicht , truewenn sie durch Ihre Funktion setzen.

Ihre Frage bezieht sich jedoch auf die bitweise Operation auf einem Booleschen Wert. Da Operatoren Ganzzahlen mögen >>und damit <<arbeiten, konvertiert Javascript zuerst den booleschen Wert in eine Ganzzahl. So truewird 1 und falsewird 0. Um dies zu sehen, können Sie um Null verschieben:

console.log("true is",true >> 0)
console.log("false is", false >> 0)
Die bitweise Operation auf Booleschen Werten ist also wirklich nur die bitweise Operation auf 0 oder 1.

Die Verwendung !!ist eine praktische Möglichkeit, etwas in einen Booleschen Wert umzuwandeln. Es etwas nimmt , das entspricht falsch angesehen werden würde (wie 0, null, undefinedoder „“) und gibt zurück false. Ebenso alles, was wahr ist (wie 14, "Hallo", [4], {a: 1}) und zurückgeben true. !!funktioniert, weil das erste Ausrufezeichen das 'nicht' des Ausdrucks angibt, der immer trueoder ist false, und das zweite Ausrufezeichen das Gegenteil von dem ( falseoder true) gibt.

Um auf die Herausforderung zurückzukommen, möchte es den Nicht-Operator 'a' mal anwenden und mit dem 'b'-Wert vergleichen. So etwas würde funktionieren:

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

Immer lernen
quelle
9
Ich denke, die "Herausforderung" möchte wirklich, dass Sie erkennen, dass Sie dies problemlos ohne Schleife tun können ...
BlueRaja - Danny Pflughoeft
2
@ BlueRaja-DannyPflughoeft in der Tat. Der einfachste Weg, dies ohne Schleife zu tun, ist, if (a % 2 === 1) return !b else return baber wie in anderen Antworten gezeigt, gibt es Möglichkeiten, dies ohne Verzweigung oder Schleifen zu tun.
VLAZ
Ja, aber bei der Frage ging es nicht darum, die Herausforderung zu meistern, sondern darum, wie bitweise Operator- und Boolesche Werte vorliegen. Aber ich habe meine Antwort mit einer Nicht-Schleife und einer Nicht-Wenn-Methode aktualisiert.
Immer lernen
14

Bitweise Operatoren konvertieren ihre Operanden immer in eine Ganzzahl. Es 4 >> trueist also dasselbe, mit 4 >> 1dem eine Bitverschiebung um eine Position nach rechts ausgeführt wird

(decimal) 4 = (binary) 100

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

(binary) 010 = (decimal) 2

console.log(4 >> true);

Die Verwendung von trueoder falseist also nur ein Umweg, um 1oder zu verwenden 0.

Die notNotNotFunktion ist insgesamt sehr einfach zu bedienen:

  1. a%2wandelt die erste Zahl in 0gerade oder 1ungerade um.
  2. >> bverschiebt sich entweder um 0Positionen für falseoder 1Position für nach rechts true.
    • aist ungerade (1) und bist false=1
      • Es gibt keine Verschiebungen nach rechts, daher bleibt die Zahl gleich.
    • aist ungerade (1) und bist true=0
      • Das einzige gesetzte Bit 1wird nach rechts verschoben und verworfen.
    • aist gerade (0) und bist false=0
      • Es gibt keine Verschiebungen nach rechts, daher bleibt die Zahl gleich.
    • aist gerade (0) und bist true=0
      • Die Basisnummer ist 0die, für die keine Bits gesetzt sind. Wenn Sie also einen beliebigen Betrag nach rechts verschieben, ändert sich dies nicht.
  3. !!() konvertiert das Ergebnis in einen Booleschen Wert.

Trotzdem ist die Lösung hier falsch, da notNotNot(2, true)sie produzieren wird false- aist gerade und bist true. Die Erwartung ist, dass es trueseitdem produzieren wird !!true = true. Das gleiche Problem besteht für jede gerade Zahl und true.

Es kann leicht behoben werden, indem bitweises XOR anstelle der Rechtsverschiebung verwendet wird:

  • aist ungerade (1) und bist false=1
    • beide stimmen überein, also werden sie umgedreht 0
  • aist ungerade (1) und bist true=0
    • Sie passen nicht zusammen, also bekommen wir 1
  • aist gerade (0) und bist false=0
    • beide passen zusammen, also bekommen wir 0
  • aist gerade (0) und bist true=1
    • Sie passen nicht zusammen, also bekommen wir 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))

Nur der Vollständigkeit halber, falls Sie eine vollständig bitweise Operation wünschen:

Die Modulo-Operation %2kann bitweise geändert werden UND &1das niedrigste Bit erhalten. Für gerade Zahlen würde dies ergeben, 0da Sie rechnen würden

xxx0
&
0001

Das ist Null. Und für ungerade Zahlen gilt das Gleiche, aber Sie erhalten eine als Ergebnis:

xxx1
&
0001

Die Ergebnisse von a&1und a%2sind also identisch. Auch wenn bitweise Operationen die Zahl in eine 32-Bit-Ganzzahl mit Vorzeichen konvertieren , spielt dies keine Rolle, da die Parität erhalten bleibt.

VLAZ
quelle
4

Erstens (a,b) => !!(a%2 >> b)stimmt nicht mit den Ergebnissen der Beispiele überein. Ich werde genau aufschlüsseln, was es macht notNotNot(6, true) ➞ true.

  • Faust a%2, einfach adurch 2 teilen, den Rest zurückgeben. Wir erhalten also 0 für eine gerade Zahl und 1 für eine ungerade Zahl. a = 6 a%2 = 0in diesem Fall.
  • Dann 0 >> bverschieben Sie 1 Zahl von rechts weg, weil, wie Sie sagten, trueausgewertet wird 1. Also bekommen wir 0 >> 1 = 0.
  • Zuletzt !!(0)ist einfach und kann wie, so abgebaut werden !0 = true, dann !true = false.

Also , wenn wir denken , dass dies etwa so lang wie bist true, werden wir immer wieder bekommen false. Nehmen wir an, wir haben a = 5, b = wahr, um zu bewerten 5%2 = 1, 1 >> 1 = 0. Sie können sehen, dass %2wir aufgrund von mod ( ) immer nur 1 oder 0 haben (immer nur 1 Ziffer haben) und true immer die 1 abschaltet, wenn wir sie haben.

Eine einfache Möglichkeit, dieses Problem zu betrachten, ist wie eine isEvenOrNotFunktion. Dies agilt auch für die Zahl, die wir überprüfen, und bist ein Boolescher Wert, um zu überprüfen, ob sie gerade (wahr) oder nicht gerade (falsch) ist. Dies funktioniert, weil jede nothinzugefügte Sekunde wahr ist.

Eine Lösung mit bitweiser Lösung könnte also etwa so aussehen : (a,b) => !!(a&1 ^ b). Ich werde Ihnen den Spaß machen, herauszufinden, warum es funktioniert! :) :)

Ein bisschen mehr in die Erklärung, wie Shift mit einem Booleschen Wert funktioniert. So truewie Sie gesagt haben 1 sein und falsch wird in Ihrem Beispiel 0. So wie dargestellt sein, 0101 >> trueist das gleiche wie 0101 >> 1.

Ich hoffe das hilft.

Ich habe Folgendes als Referenz für bitweise verwendet: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators

domsim1
quelle
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

Hinweis: Bei beiden Booleschen Werten führt eine gerade Anzahl von NOTs zum ursprünglichen Booleschen Wert. Eine ungerade Anzahl von NOTs führt zum entgegengesetzten Booleschen Wert

Das LSB einer beliebigen Zahl bestimmt, ob die Zahl ungerade oder gerade ist (0 gerade, 1 ungerade).

Stephen Duffy
quelle
1

Ich sehe, dass Ihre Aufgabe ist:

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

Ich weiß nicht, warum Sie eine notnotnotFunktion für mich schreiben , die die Aufgabe nicht verlangt.

Entsprechend der Aufgabe habe ich diese Funktion erstellt not , die eine Reihe von "Nots" akzeptiert und diese auswertet.

Der erste Weg

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

Der zweite Weg mit XOr (^)

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

Der dritte Weg mit Mod (%), auf den @VLAZ zeigt

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

Der vierte Weg mit bitweisem And (&)

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

Prüfung

not(0)
//> false 
not(1)
//> true
not(2)
//> false
not(515)
//> true
SaymoinSam
quelle
1
Bitmanipulation ist hier nützlich, da wir uns nicht um den Betrag kümmern n- nur ob er gerade oder ungerade ist, da sich zwei beliebige NOTs aufheben, also !!!!!bdasselbe wie !b. Daher brauchen wir keine Schleife, wenn wir nur nehmen n%2- wir würden 1für NICHT und 0für "Gleich bleiben" bekommen. Da wir eine Nummer haben, können wir nur bitweise Operationen ausführen.
VLAZ
Nun, darüber habe ich nicht nachgedacht, aber Sie haben Recht, wir haben es nur mit 0 und 1 zu tun, danke, dies ist ein nützlicher Kommentar :)
SaymoinSam
0

Lässt zuerst die Analyselösung

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

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

Analysieren Sie nun das für (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

Das ist Mittel , dies ist nicht für die Arbeit notNotNot(6, true)ist trueaber die aktuelle Lösung gibt false.

Wir können Sie ^(XOR) Operator, um es richtig zu machen(a,b) => !!(a%2 ^ b)

Analysieren Sie nun das für (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.

Beispiel:

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
quelle