Làm thế nào để hoạt động bitwise trên Booleans?


26

Tôi đã gặp thử thách này trên Edabit và không thể tìm ra giải pháp vận hành bitwise này.

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

Các thách thức:

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

Tôi đã làm một số nghiên cứu mà nhà điều hành:

Chuyển sang phải bằng cách đẩy các bản sao của bit ngoài cùng bên trái từ bên trái và để các bit ngoài cùng bên phải rơi ra.

Rằng tôi nghĩ rằng tôi đã hiểu (ví dụ 5 >> 1như 0101 >> 1đánh giá 0010), nhưng tôi không thể thấy nó hoạt động như thế nào với boolean? Tôi biết trueđánh giá 1falseđể 0.


3
Một boolean sẽ được chuyển thành một số và sau đó sự thay đổi sẽ xảy ra, vì vậy true= 1(thập phân) = 01(nhị phân) được dịch chuyển bởi một người sẽ tạo ra 10nhị phân hoặc 2thập phân.
VLAZ

Trên thực tế, giải pháp này là không chính xác. Trong các trường hợp nêu trên, nó sẽ hoạt động, nhưng hãy xem xét notNotNot(2, true): nó sẽ trở lại false, nhưng không phải là sự thật ( !!true) nên true...
FZs

@FZs đúng. Hàm sẽ chỉ xem xét một số lượng nhỏ các ký hiệu trên a falseđể giải quyết true.
VLAZ

2
notNotNot = (a,b) => !!((a%2)^b)Thay vào đó tôi sẽ nói ...
FZs

Tại sao không chỉ (a, b) => !!((a + b) % 2)?
Jonas Wilms

Câu trả lời:


16

Chức năng bạn đưa ra không thỏa mãn thách thức. Dịch chuyển phải sẽ không làm những gì được yêu cầu. Ví dụ, bạn notNotNot(6,true)false, không phải truekhi đặt thông qua chức năng của bạn.

Câu hỏi của bạn là về hoạt động bitwise trên một boolean mặc dù. Do các toán tử thích >><<làm việc trên các số nguyên, trước tiên Javascript chuyển đổi giá trị boolean thành một số nguyên. Vì vậy, truetrở thành 1 và falsetrở thành 0. Để thấy điều này, bạn có thể thay đổi bằng 0:

console.log("true is",true >> 0)
console.log("false is", false >> 0)
Vì vậy, hoạt động bitwise trên booleans thực sự chỉ là hoạt động bitwise trên 0 hoặc 1.

Sử dụng !!là một cách tiện dụng để chuyển đổi bất cứ thứ gì thành boolean. Nó nhận bất cứ thứ gì được coi là tương đương với sai (chẳng hạn như 0 null, undefinedhoặc "") và trả lại false. Tương tự bất cứ điều gì là sự thật (như 14, "xin chào", [4], {a: 1}) và trả lại true. !!hoạt động vì dấu chấm than đầu tiên cho 'không' của biểu thức luôn luôn truehoặc false, sau đó dấu chấm than thứ hai cho ngược lại với biểu thức đó ( falsehoặc true).

Quay trở lại với thử thách, nó muốn áp dụng 'a' lần không phải toán tử và so sánh với giá trị 'b'. Vì vậy, một cái gì đó như thế này sẽ làm việc:

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
Tôi nghĩ rằng "thử thách" thực sự muốn bạn nhận ra bạn có thể dễ dàng thực hiện điều này mà không cần vòng lặp ...
BlueRaja - Danny Pflughoeft

2
@ BlueRaja-DannyPflughoeft thực sự. Cách đơn giản nhất để làm điều đó mà không có vòng lặp là if (a % 2 === 1) return !b else return bnhưng như trong các câu trả lời khác, có nhiều cách để làm điều đó mà không cần phân nhánh hoặc vòng lặp.
VLAZ

đúng, nhưng câu hỏi không phải là về việc thực hiện thử thách - đó là về cách các giá trị toán tử và boolean bitwise. Nhưng tôi đã cập nhật câu trả lời của mình bằng cách không vòng lặp và không nếu.
Luôn học

14

Toán tử bitwise luôn chuyển đổi toán hạng của chúng thành một số nguyên. Vì vậy, 4 >> truegiống như 4 >> 1sẽ làm một chút thay đổi ngay tại một vị trí

(decimal) 4 = (binary) 100

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

(binary) 010 = (decimal) 2

console.log(4 >> true);

Vì vậy, sử dụng truehoặc falsechỉ là một cách vòng để sử dụng 1hoặc 0.

Các notNotNotchức năng có hoạt động rất đơn giản, tổng thể:

  1. a%2chuyển đổi số đầu tiên thành số 0chẵn hoặc 1lẻ.
  2. >> bthay đổi bên phải bởi 0vị trí cho falsehoặc 1vị trí cho true.
    • alà số lẻ (1) và bfalse=1
      • không có dịch chuyển về bên phải, vì vậy số lượng vẫn giữ nguyên.
    • alà số lẻ (1) và btrue=0
      • bit thiết lập duy nhất 1được dịch chuyển sang phải và bị loại bỏ.
    • alà chẵn (0) và bfalse=0
      • không có dịch chuyển về bên phải, vì vậy số lượng vẫn giữ nguyên.
    • alà chẵn (0) và btrue=0
      • số cơ sở 0không có bất kỳ bit nào được đặt, do đó, việc chuyển đúng bất kỳ số tiền nào sẽ không thay đổi nó.
  3. !!() chuyển đổi kết quả thành boolean.

Như đã nói, giải pháp ở đây là sai, vì notNotNot(2, true)sẽ sản xuất false- alà thậm chí và btrue. Kỳ vọng là nó sẽ sản xuất truekể từ đó !!true = true. Vấn đề tương tự hiện diện cho bất kỳ số chẵn và true.

Nó có thể dễ dàng được sửa bằng cách sử dụng XOR bitwise thay vì dịch chuyển phải:

  • alà số lẻ (1) và bfalse=1
    • cả hai khớp nhau, vì vậy chúng được lật sang 0
  • alà số lẻ (1) và btrue=0
    • họ không hợp nhau, vì vậy chúng tôi nhận được 1
  • alà chẵn (0) và bfalse=0
    • cả hai trận đấu, vì vậy chúng tôi nhận được 0
  • alà chẵn (0) và btrue=1
    • họ không hợp nhau, vì vậy chúng tôi nhận được 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))

Chỉ vì lợi ích hoàn toàn, trong trường hợp bạn muốn thao tác hoàn toàn theo bit:

Hoạt động modulo %2có thể được thay đổi thành bitwise VÀ &1lấy bit thấp nhất. Đối với các số chẵn, điều này sẽ mang lại 0vì bạn đang tính toán

xxx0
&
0001

bằng không. Và đối với các số lẻ áp dụng tương tự, nhưng bạn sẽ nhận được một kết quả:

xxx1
&
0001

Vì vậy, kết quả của a&1a%2là giống hệt nhau. Hơn nữa, mặc dù các phép toán bitwise chuyển đổi số thành số nguyên có chữ ký 32 bit không quan trọng vì tính chẵn lẻ sẽ được giữ nguyên.


4

Thứ nhất, (a,b) => !!(a%2 >> b)không phù hợp với kết quả của các ví dụ. Tôi sẽ chia nhỏ chính xác những gì nó đang sử dụng notNotNot(6, true) ➞ true.

  • Nắm tay a%2, chỉ cần nhận được achia cho 2 trả lại phần còn lại. Vì vậy, chúng tôi sẽ nhận được 0 cho một số chẵn và 1 cho một số lẻ. a = 6 a%2 = 0trong trường hợp này.
  • Sau đó 0 >> bthay đổi 1 số từ bên phải bởi vì như bạn đã nói trueđánh giá 1. Vì vậy, chúng tôi nhận được 0 >> 1 = 0.
  • Cuối cùng !!(0), là đơn giản, và có thể được chia nhỏ như vậy !0 = true, sau đó !true = false.

Vì vậy, nếu chúng ta nghĩ về điều này miễn là btrue, chúng ta sẽ luôn được trả lại false. Giả sử chúng ta có a = 5, b = đánh giá đúng 5%2 = 1, 1 >> 1 = 0. Bạn có thể thấy vì mod ( %2) chúng ta sẽ chỉ có 1 hoặc 0 (chỉ bao giờ có 1 chữ số) và true sẽ luôn thay đổi 1 khi chúng ta có nó.

Một cách đơn giản để xem xét vấn đề này giống như một isEvenOrNotchức năng. Vì vậy, asố lượng chúng tôi đang kiểm tra và blà một boolean để kiểm tra xem nó là chẵn (đúng) hay thậm chí (sai). Điều này hoạt động bởi vì mỗi giây notthêm vào sẽ là sự thật.

Vì vậy, một giải pháp sử dụng bitwise có thể là một cái gì đó như : (a,b) => !!(a&1 ^ b). Tôi sẽ cho bạn có niềm vui phá vỡ tại sao nó hoạt động! :)

Một chút nữa để giải thích làm thế nào sự thay đổi làm việc với một boolean. Vì vậy, truenhư bạn đã nói sẽ là 1 và sai sẽ là 0. Vì vậy, như trong ví dụ của bạn, 0101 >> truecũng giống như 0101 >> 1.

Tôi hi vọng cái này giúp được.

Tôi đã sử dụng thông tin sau đây làm tài liệu tham khảo cho bitwise: 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

NB Đối với một trong hai boolean, một số lượng chẵn các kết quả KHÔNG trong boolean ban đầu, một số lượng lẻ các kết quả KHÔNG trong các boolean ngược lại

LSB của bất kỳ số nào cho biết số đó là số lẻ hay số chẵn. (0 chẵn, 1 số lẻ)


1

Tôi thấy rằng nhiệm vụ của bạn là:

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

Tôi không biết tại sao bạn viết notnotnothàm cho tôi mà không phải là nhiệm vụ yêu cầu.

Vì vậy, theo nhiệm vụ tôi đã thực hiện chức năng not đó chấp nhận một số "nots" và đánh giá chúng.

Cách thứ nhất

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

Cách thứ hai sử dụng XOr (^)

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

Cách thứ ba sử dụng Mod (%) được chỉ ra bởi @VLAZ

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

Cách thứ tư sử dụng bitwise Và (&)

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

Kiểm tra

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

1
Thao tác bit rất hữu ích ở đây, vì chúng tôi không quan tâm đến số tiền n- chỉ cho dù đó là số chẵn hay lẻ, vì bất kỳ hai KHÔNG phải hủy bỏ, !!!!!bcũng giống như vậy !b. Do đó, chúng tôi không cần một vòng lặp nếu chúng tôi chỉ thực hiện n%2- chúng tôi sẽ nhận được 1KHÔNG và 0vì "giữ nguyên như vậy". Vì chúng ta có một số, chúng ta chỉ có thể thực hiện các thao tác bitwise.
VLAZ

Chà, tôi đã không nghĩ về điều đó nhưng bạn nói đúng, chúng tôi chỉ giao dịch với 0 và 1, cảm ơn bạn, đây là một nhận xét hữu ích :)
SaymoinSam

0

Cho phép giải pháp phân tích trước

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

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

Bây giờ phân tích cho (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 phương tiện này không được làm việc cho notNotNot(6, true)truenhưng giải pháp hiện tại cho phép false.

Chúng tôi có thể bạn ^(XOR) toán tử để làm cho nó đúng(a,b) => !!(a%2 ^ b)

Bây giờ phân tích cho (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.

Thí dụ:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.