布尔运算如何按位运算?


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 >> 10101 >> 1计算结果相同0010),但是我看不到布尔值如何工作?我知道true1false进行评估0


3
布尔值将被转换为数字,然后将发生移位,因此true= 1(十进制)= 01(二进制)左移一位将产生10二进制或2十进制。
VLAZ

实际上,此解决方案是不正确的。在上述情况下,它将起作用,但请考虑notNotNot(2, true):它将返回false,但不是真的(!!true)应该是true...
FZs

@FZ是正确的。该函数将仅考虑false要解析为的奇数个not true
VLAZ

2
我会说notNotNot = (a,b) => !!((a%2)^b)...
FZs

为什么不只是(a, b) => !!((a + b) % 2)
Jonas Wilms

Answers:


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进行按位运算。

使用!!是将任何内容转换为布尔值的便捷方法。它接受任何被认为等同于false的东西(例如0 nullundefined或“”)并返回false。同样,任何真实的东西(例如14,“ hello”,[4],{a:1})并退还true!!之所以有效,是因为第一个感叹号给出了始终为true或的表达式的“ not” false,然后第二个感叹号给出了与(falsetrue)相反的表达式。

回到挑战,它希望应用非运算符“ 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但是如其他答案所示,有一些没有分支或循环的方法。
VLAZ

是的,但是问题不在于挑战,而是关于运算符和布尔值的按位运算。但是,我已经以非循环和非if的方式更新了我的答案。
总是学习

14

按位运算符始终将其操作数转换为整数。因此,4 >> true4 >> 1将右移一个位置的位置相同

(decimal) 4 = (binary) 100

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

(binary) 010 = (decimal) 2

console.log(4 >> true);

因此,使用true或者false是只用一种迂回的方式10

notNotNot功能操作非常简单,总体来说:

  1. a%2将第一个数字转换0为偶数或1奇数。
  2. >> b位移通过任一合适的0位置为false1用于位置true
    • a是奇数(1)并且bfalse=1
      • 右移为零,因此数字保持不变。
    • a是奇数(1)并且btrue=0
      • 唯一的设置位1被右移并丢弃。
    • a为偶数(0)和bfalse=0
      • 右移为零,因此数字保持不变。
    • a为偶数(0)和btrue=0
      • 0没有设置任何位的基数,因此向右移任何数量都不会更改它。
  3. !!() 将结果转换为布尔值。

话虽如此,这里的解决方案是错误的,因为notNotNot(2, true)将产生false- a偶数和bis true。预期它将true自产生!!true = true。任何偶数和都存在相同的问题true

通过使用按位XOR而不是右移,可以轻松修复它:

  • a是奇数(1)并且bfalse=1
    • 两者都匹配,所以它们被翻转到 0
  • a是奇数(1)并且btrue=0
    • 他们不匹配,所以我们得到 1
  • a为偶数(0)和bfalse=0
    • 两者都匹配,所以我们得到 0
  • a为偶数(0)和btrue=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&1a%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个数字,因为正如您所说的,结果true1。这样我们就可以了0 >> 1 = 0
  • 最后!!(0),很简单,可以像这样分解!0 = true,然后!true = false

因此,如果我们想一想,只要btrue,我们总是会得到恢复false。假设我们有a = 5,b = true,计算5%2 = 11 >> 1 = 0。您可以看到由于mod(%2),我们将永远只有1或0(只有1位数字),而true总是在我们拥有1或0的情况下转移。

解决此问题的简单方法就像一个isEvenOrNot函数。所以,a是我们正在检查的数量,b是一个布尔值,以检查它是否是偶数(true)或者甚至没有(假)。之所以有效,是因为每一秒钟not是添加的都是正确的。

因此,使用按位解决方案可能类似于:(a,b) => !!(a&1 ^ b)。我将让您有乐趣来分解它为什么起作用!:)

多一点解释布尔如何转换。所以,true像你说的将是1和假将是0,所以在您的例子所示,0101 >> true是一样的0101 >> 1

我希望这有帮助。

我将以下内容用作按位的参考:https : //developer.mozilla.org/zh-CN/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

注意对于任一布尔值,偶数个NOT会导致原始布尔值,而奇数个NOTS会导致相反的布尔值

任何数字的LSB决定该数字是奇数还是偶数(0偶数,1奇数)


1

我看到您的任务是:

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

我不知道你为什么写作 notnotnot为我函数,而不是任务所要求的。

所以根据任务我做了那个功能 not 接受了许多“ not”并对其进行求值。

第一种方式

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

使用XOr(^)的第二种方式

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

@VLAZ指向的使用Mod(%)的第三种方式

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

使用按位And(&)的第四种方式

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

测试

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

1
此处的位操作非常有用,因为我们不在乎数量n-只关心它是偶数还是奇数,因为任何两个NOT都被抵消,所以!!!!!b与相同!b。因此,如果我们只是采取循环,就不需要循环n%2-我们会得到1NOT和0“保持不变”。由于我们有一个数字,所以我们可以进行按位运算。
VLAZ

好吧,我没有考虑这一点,但您是对的,我们只处理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)运算符来使它正确吗喜欢(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))

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.