Яким чином бітова операція працює на Booleans?


26

Я зіткнувся з цим завданням на Edabit і не зміг розробити це розрядне рішення операції.

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

Змагання:

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

Я зробив кілька досліджень, що цей оператор:

Зсуває праворуч, натискаючи на копії крайнього лівого біта зліва, і нехай кращі праворучі відпадають.

Що я вважаю, я зрозумів (наприклад, 5 >> 1те, 0101 >> 1що оцінює 0010), але я не бачу, як це працює з булевим? Я знаю, що trueоцінює до 1і falseдо 0.


3
Булевий просто перетворюється на число, і тоді відбудеться зсув, тому true= 1(десяткова) = 01(двійкова) зміщена вліво на одиницю створює 10двійкове чи 2десяткове.
ВЛАЗ

Власне, це рішення неправильне. У вищезгаданих випадках це спрацює, але врахуйте notNotNot(2, true): повернеться false, але не неправда ( !!true) має бути true...
FZs

@FZs це правильно. Функція буде враховувати лише непарне число nots на a falseдля вирішення true.
ВЛАЗ

2
Я б сказав, notNotNot = (a,b) => !!((a%2)^b)замість цього ...
FZs

Чому б не просто (a, b) => !!((a + b) % 2)?
Йонас Вілмс

Відповіді:


16

Функція, яку ви надали, не відповідає виклику. Зміна вправо не зробить те, про що вимагають. Наприклад, ваш notNotNot(6,true)єfalse , а не trueтоді, коли ви перебуваєте через свою функцію.

Ваше запитання - про побітну операцію на булевій. Оскільки оператори люблять >>і <<працюють над цілими числами, Javascript спочатку перетворює булеве значення в ціле число. Так trueстає 1 і falseстає 0. Щоб побачити це, ви можете змістити на нуль:

console.log("true is",true >> 0)
console.log("false is", false >> 0)
Тож побітова операція на булевих операціях насправді є просто бітовою операцією на 0 або 1.

Використання !!- це зручний спосіб перетворити що-небудь у булевий. Він бере все, що було б визнано рівнозначним помилковому (наприклад, 0 null, undefinedабо "") і повертає назад false. Аналогічно все, що є правдою (наприклад, 14, "привіт", [4], {a: 1}) і повертайте назад true.!!працює , тому що перший знак оклику дає «не» вираз , яке завжди trueабо false, то другий знак оклику дає протилежний , що (false або true).

Повертаючись до виклику, він хоче застосувати "a" рази не-оператора та порівняти зі значенням "b". Отже, щось подібне спрацювало б:

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


9
Я думаю, що "виклик" дуже хоче, щоб ти зрозумів, що ти можеш легко зробити це без петлі ...
BlueRaja - Danny Pflughoeft

2
@ BlueRaja-DannyPflughoeft справді. Найпростіший спосіб зробити це без циклу, if (a % 2 === 1) return !b else return bале там, як показано в інших відповідях, є способи зробити це без розгалуження або циклів.
ВЛАЗ

так, але питання полягало не в тому, щоб робити виклик - це про те, як розрядні значення оператора та булеві значення. Але я оновив свою відповідь не в циклі, а в інший спосіб.
Завжди навчаюся

14

Побітові оператори завжди перетворюють свої операнди в ціле число. Отже, 4 >> trueце те саме, 4 >> 1що зробить трохи зрушення прямо на одну позицію

(decimal) 4 = (binary) 100

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

(binary) 010 = (decimal) 2

console.log(4 >> true);

Отже, використання trueабо falseє просто круговим способом використання 1або0 .

У notNotNotцілому функція має дуже просте управління:

  1. a%2перетворює перше число в 0парне або1 непарне.
  2. >> bзміщується вправо на будь-яку 0позицію для falseабо 1позицію дляtrue .
    • aнепарній (1) , і bце false=1
      • відбувається зсув нуля вправо, тому число залишається тим самим.
    • aнепарній (1) , і bце true=0
      • єдиний встановлений біт 1зміщується вправо і відкидається.
    • aє рівним (0) і bє false=0
      • відбувається зсув нуля вправо, тому число залишається тим самим.
    • aє рівним (0) і bє true=0
      • базовий номер 0не містить жодних бітів, тому зміщення вправо будь-якої суми не змінює його.
  3. !!() перетворює результат на булевий.

З урахуванням сказаного, рішення тут неправильне, оскільки notNotNot(2, true)буде виробляти false- aрівномірне і bє true. Очікується, що вона буде виробляти trueз того часу !!true = true. Ця ж проблема є для будь-якого парного числа іtrue .

Це можна легко виправити за допомогою бітового XOR замість правого зсуву:

  • aнепарній (1) , і bце false=1
    • обидва відповідають, тому вони перекинуті 0
  • aнепарній (1) , і bце true=0
    • вони не відповідають, тому ми отримуємо 1
  • aє рівним (0) і bє false=0
    • обидва відповідають, так що ми отримуємо 0
  • aє рівним (0) і bє true=1
    • вони не відповідають, тому ми отримуємо 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))

Просто для повноти, якщо ви хочете повністю розрядну операцію:

Операцію модуля %2можна змінити на побіт І &1отримати найнижчий біт. Для парних чисел це призведе до отримання 0обчислень

xxx0
&
0001

що дорівнює нулю. І для непарних чисел те саме стосується, але ви отримаєте його в результаті:

xxx1
&
0001

Тож результати a&1і a%2однакові. Крім того, навіть якщо побітові операції перетворюють число в 32-розрядне підписане ціле число, що не має значення, як паритет буде збережений.


4

По-перше, (a,b) => !!(a%2 >> b)не відповідає результатам прикладів. Я розберу саме те, що він робить, використовуючи notNotNot(6, true) ➞ true.

  • Кулак a%2, просто aділити на 2 повернути залишок. Таким чином, ми отримаємо 0 для парного числа і 1 для непарного числа. a = 6 a%2 = 0в цьому випадку.
  • Потім 0 >> bзмістіть 1 число від правого, тому що, як ви сказали, trueоцінюється до 1. Таким чином ми отримуємо 0 >> 1 = 0.
  • Останнє !!(0), проста, і може бути розбита , як це так, !0 = true, а потім !true = false.

Тож якщо ми будемо думати про це до тих пір, поки bє true, ми завжди будемо повертатися false. Припустимо, ми маємо = 5, Ь = вірно обчислювані 5%2 = 1, 1 >> 1 = 0. Ви можете бачити, що через mod ( %2) у нас буде колись 1 або 0 (тільки коли-небудь 1 цифра), а true завжди змістить 1, коли у нас є.

Простий спосіб поглянути на цю проблему - це як isEvenOrNotфункція. Так aсамо число, яке ми перевіряємо, і bє булевим, щоб перевірити, чи воно рівне (справжнє) чи навіть не (помилкове). Це працює, тому що кожна секунда, що notдодається, буде правдою.

Таким чином, рішення з використанням побітового може бути що - щось на кшталт: (a,b) => !!(a&1 ^ b). Я дозволю вам повеселитись розбивати, чому це працює! :)

Ще трохи в поясненні того, як shift працює з булевим. Отже, trueяк ви сказали, буде 1, а помилковим буде 0. Так, як показано у вашому прикладі, 0101 >> trueце те саме, що 0101 >> 1.

Я сподіваюся, що це допомагає.

Я використовував таке посилання для побітових даних: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators


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

Примітка. Для будь-якого булевого числа, парне число NOTs призводить до початкового булевого числа, а непарна кількість NOT - результатів, що мають протилежний булевий

LSB будь-якого числа диктує, чи число непарне чи парне (0 парне, 1 непарне)


1

Я бачу, що ваше завдання:

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

Я не знаю, чому ти пишеш notnotnot функцію для мене, це не те, що задає завдання.

Тож згідно із завданням я зробив цю функцію not яка приймає ряд "nots" та оцінює їх.

Перший спосіб

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

Другий спосіб використання XOr (^)

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

Третій спосіб використання Mod (%), вказаний @VLAZ

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

Четвертий спосіб, що використовує побітне значення І (&)

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

Тест

not(0)
//> false 
not(1)
//> true
not(2)
//> false
not(515)
//> true

1
Тут корисна маніпуляція nз бітами , оскільки ми не байдуже на суму - лише те, чи є парною чи непарною, оскільки будь-які два NOTS скасовують, так !!!!!bсамо як !b. Отже, нам не потрібна петля, якщо ми просто візьмемо n%2- ми отримаємо 1НЕ та 0"збережіть те саме". Оскільки у нас є номер, ми можемо просто робити побітові операції.
ВЛАЗ

Ну, я не думав про це, але ви маєте рацію, ми маємо справу лише з 0 і 1, дякую, це корисний коментар :)
SaymoinSam

0

Розглянемо спочатку рішення для аналізу

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

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

Тепер проаналізуйте для (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

Це означає, що це не працює notNotNot(6, true), trueале поточне рішення даєfalse .

Ми можемо вам ^(XOR) оператора, щоб зробити його правильним Like(a,b) => !!(a%2 ^ b)

Тепер проаналізуйте для (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.

Приклад:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.