Jak działa bitowa operacja na booleanach?

26

Natknąłem się na to wyzwanie na Edabit i nie mogłem znaleźć tego rozwiązania operacji bitowej.

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

Wyzwanie:

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

Zrobiłem badania, które ten operator:

Przesuwa w prawo, popychając kopie najbardziej wysuniętego w lewo bitu od lewej i pozwól, aby bity najbardziej wysunięte w prawo wypadły.

Wydaje mi się, że zrozumiałem (np. To 5 >> 1samo, 0101 >> 1co ocenia 0010), ale nie widzę, jak to działa z wartością logiczną? Wiem, że trueocenia 1i falsedo 0.

kiabbott
źródło
3
Wartość logiczna zostanie właśnie przekształcona na liczbę, a następnie nastąpi przesunięcie, więc true= 1(dziesiętny) = 01(dwójkowy) przesunięty w lewo o jeden spowoduje 10binarny lub 2dziesiętny.
VLAZ
W rzeczywistości to rozwiązanie jest nieprawidłowe. W wyżej wymienionych przypadkach będzie działać, ale zastanów się notNotNot(2, true): powróci false, ale nieprawda ( !!true) powinna być true...
FZs
@ FZs to prawda. Funkcja bierze pod uwagę tylko nieparzystą liczbę notek nafalse należy rozstrzygnąć true.
VLAZ
2
Powiedziałbym notNotNot = (a,b) => !!((a%2)^b)zamiast tego ...
FZs
Dlaczego nie tylko (a, b) => !!((a + b) % 2)?
Jonas Wilms

Odpowiedzi:

16

Podana funkcja nie spełnia wyzwania. Właściwa zmiana biegów nie spełni oczekiwań. Na przykład twój notNotNot(6,true)jest false, nietrue w momencie oddania za pośrednictwem funkcji.

Twoje pytanie dotyczy bitowej operacji na wartości logicznej. Ponieważ operatorzy lubią >>i <<pracują na liczbach całkowitych, Javascript najpierw konwertuje wartość logiczną na liczbę całkowitą. Więc truestaje się 1 i falsestaje się 0. Aby to zobaczyć, możesz przesunąć o zero:

console.log("true is",true >> 0)
console.log("false is", false >> 0)
Tak więc operacja bitowa na boolach jest tak naprawdę operacją bitową na 0 lub 1.

Używanie !!to przydatny sposób na konwersję czegokolwiek na wartość logiczną. To trwa niczego, co mogłoby być uznane za równoważne z false (takich jak 0, null, undefinedlub „”) i daje z powrotemfalse . Podobnie wszystko, co jest prawdą (jak 14, „cześć”, [4], {a: 1}) i oddaj true. !!działa, ponieważ pierwszy wykrzyknik podaje „nie” wyrażenia, które jest zawsze truelub false, a następnie drugi wykrzyknik daje przeciwieństwo tego ( falselub true).

Wracając do wyzwania, chce zastosować czasy nie będące operatorem „a” i porównać je z wartością „b”. Więc coś takiego działałoby:

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

Zawsze się uczę
źródło
9
Myślę, że „wyzwanie” naprawdę chce, abyś zdał sobie sprawę, że możesz to łatwo zrobić bez pętli ...
BlueRaja - Danny Pflughoeft
2
@ BlueRaja-DannyPflughoeft rzeczywiście. Najprostszym sposobem, aby to zrobić bez pętli, jest if (a % 2 === 1) return !b else return bto, jak pokazano w innych odpowiedziach, istnieją sposoby, aby to zrobić bez rozgałęzień lub pętli.
VLAZ
tak, ale pytanie nie dotyczyło wykonania wyzwania - chodziło o to, jak operator bitowy i wartości logiczne. Ale zaktualizowałem swoją odpowiedź w sposób niepętlowy i nie-jeśli.
Zawsze uczę się
14

Operatory bitowe zawsze przekształcają operandy na liczby całkowite. Tak więc 4 >> truejest to to samo, 4 >> 1co spowoduje nieznaczne przesunięcie w prawo o jedną pozycję

(decimal) 4 = (binary) 100

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

(binary) 010 = (decimal) 2

console.log(4 >> true);

Tak więc użycie truelub falsejest tylko rondem do użycia 1lub 0.

notNotNotFunkcja ma bardzo prostą obsługę, ogólnie:

  1. a%2konwertuje pierwszą liczbę na 0parzystą lub 1nieparzystą.
  2. >> bprzesuwa się w prawo o 0pozycje dla falselub 1pozycję dla true.
    • ajest nieparzysty (1) i bwynosi false=1
      • po prawej stronie jest zero przesunięć, więc liczba pozostaje taka sama.
    • ajest nieparzysty (1) i bwynosi true=0
      • jedyny ustawiony bit 1jest przesunięty w prawo i odrzucony.
    • ajest parzysty (0) i bwynosi false=0
      • po prawej stronie jest zero przesunięć, więc liczba pozostaje taka sama.
    • ajest parzysty (0) i bwynosi true=0
      • numer podstawowy to taki, 0który nie ma ustawionych bitów, więc przesunięcie w prawo dowolnej kwoty nie zmienia tego.
  3. !!() konwertuje wynik na wartość logiczną.

Powiedziawszy to, rozwiązanie tutaj jest złe, ponieważ notNotNot(2, true)spowoduje , że false- abędzie parzyste i bjest true. Oczekuje się, że trueod tego czasu będzie produkować !!true = true. Ten sam problem występuje w przypadku dowolnej liczby parzystej i true.

Można to łatwo naprawić za pomocą bitowego XOR zamiast prawego przesunięcia:

  • ajest nieparzysty (1) i bwynosi false=1
    • oba pasują do siebie, więc są odwrócone 0
  • ajest nieparzysty (1) i bwynosi true=0
    • nie pasują, więc rozumiemy 1
  • ajest parzysty (0) i bwynosi false=0
    • oba pasują, więc rozumiemy 0
  • ajest parzysty (0) i bwynosi true=1
    • nie pasują, więc rozumiemy 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))

Dla zachowania kompletności, na wypadek, gdybyś chciał wykonać operację w pełni bitową:

Operację modulo %2można zmienić na bitową ORAZ &1uzyskać najniższy bit. W przypadku liczb parzystych przyniosłoby to wynik, 0ponieważ będziesz obliczał

xxx0
&
0001

która wynosi zero. W przypadku liczb nieparzystych obowiązuje to samo, ale w rezultacie otrzymasz jeden:

xxx1
&
0001

Więc wyniki a&1i a%2są identyczne. Co więcej, nawet jeśli operacje bitowe przekształcają liczbę na 32-bitową liczbę całkowitą ze znakiem, co nie ma znaczenia, ponieważ zachowana byłaby parzystość .

VLAZ
źródło
4

Po pierwsze, (a,b) => !!(a%2 >> b)nie pasuje do wyników z przykładów. Podzielę dokładnie to, co robi przy użyciu notNotNot(6, true) ➞ true.

  • Pięść a%2, po prostu apodziel się przez 2, zwróć resztę. Otrzymamy więc 0 za liczbę parzystą i 1 za liczbę nieparzystą. a = 6 a%2 = 0w tym przypadku.
  • Następnie 0 >> bprzesuń 1 cyfrę w prawo, ponieważ, jak powiedziałeś, trueocenia 1. Więc rozumiemy 0 >> 1 = 0.
  • Ostatnio !!(0), jest prosta i można rozbić jak tak !0 = true, to !true = false.

Jeśli więc zastanowimy się nad tym tak długo, jak bto truebędzie możliwe, zawsze wrócimy false. Powiedzmy, że mamy a = 5, b = true do oceny 5%2 = 1, 1 >> 1 = 0. Możesz zobaczyć ze względu na mod (%2 ), będziemy mieć tylko 1 lub 0 (zawsze tylko 1 cyfrę), a true zawsze zmieni wartość 1, gdy ją mamy.

Prosty sposób spojrzenia na ten problem jest jak isEvenOrNotfunkcja. Podobnie ajest z liczbą, którą sprawdzamy i bjest wartością logiczną, aby sprawdzić, czy jest parzysta (prawda), czy nawet parzysta (fałsz). Działa to, ponieważ każda notdodana sekunda będzie prawdziwa.

Więc rozwiązanie używając bitowego może być coś takiego: (a,b) => !!(a&1 ^ b). Pozwól, że będziesz się dobrze bawić z podziałem, dlaczego to działa! :)

Nieco więcej na temat wyjaśniania, jak shift działa z wartością logiczną. Tak truejak powiedziałeś, będzie 1, a fałsz będzie 0. Tak jak pokazano w twoim przykładzie, 0101 >> truejest to samo co 0101 >> 1.

Mam nadzieję, że to pomoże.

Użyłem następującego jako odniesienia dla bitowego: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators

domsim1
źródło
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

Uwaga: Dla obu wartości logicznych parzysta liczba NOT powoduje powstanie oryginalnej wartości logicznej, a nieparzysta liczba NOT daje przeciwną wartość logiczną

LSB dowolnej liczby decyduje, czy liczba jest nieparzysta, czy parzysta. (0 parzysta, 1 nieparzysta)

Stephen Duffy
źródło
1

Widzę, że twoim zadaniem jest:

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

Nie wiem dlaczego piszesz notnotnot dla mnie funkcję, o którą nie prosi zadanie.

Więc zgodnie z zadaniem wykonałem tę funkcję not która akceptuje wiele „not” i je ocenia.

Pierwszy sposób

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

Drugi sposób przy użyciu XOr (^)

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

Trzeci sposób korzystania z Mod (%) wskazany przez @VLAZ

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

Czwarty sposób użycia bitowego And (&)

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

Test

not(0)
//> false 
not(1)
//> true
not(2)
//> false
not(515)
//> true
SaymoinSam
źródło
1
Przydaje się tutaj manipulacja bitami, ponieważ nie zależy nam na kwocie n- tylko czy jest parzysta czy nieparzysta, ponieważ dowolne dwa NIE anulują, więc !!!!!bjest to samo co !b. Dlatego nie potrzebujemy pętli, jeśli tylko weźmiemy n%2- dostalibyśmy 1za NIE i 0za „zachowaj to samo”. Ponieważ mamy liczbę, możemy po prostu wykonywać operacje bitowe.
VLAZ
Cóż, nie myślałem o tym, ale masz rację, mamy do czynienia tylko z 0 i 1, dziękuję, to jest przydatny komentarz :)
SaymoinSam
0

Najpierw pozwala na analizę

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

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

Teraz przeanalizuj dla (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

Ów środek ten nie działa dla notNotNot(6, true)to truejednak obecne rozwiązanie daje false.

Możemy ^(XOR) operator, aby poprawić. Like(a,b) => !!(a%2 ^ b)

Teraz przeanalizuj dla (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.

Przykład:

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
źródło