How does bitwise operation work on Booleans?

The function you gave does not satisfy the challenge. Right shifting will not do what is asked for. For example, your notNotNot(6,true) is false, not true when put through your function.

Your question is about bitwise operation on a boolean though. Since operators like >> and << work on integers, Javascript first converts the boolean value to an integer. So true becomes 1 and false becomes 0. To see this you can shift by zero:

console.log("true is",true >> 0)
console.log("false is", false >> 0)
So bitwise operation on booleans is really just bitwise operation on either 0 or 1.

Using !! is a handy way to convert anything into a boolean. It takes anything that would be considered equivalent to false (such as 0, null, undefined or "") and gives back false. Similarly anything that is truthy (like 14, "hello", [4], {a:1}) and give back true. !! works because the first exclamation mark gives the 'not' of the expression which is always true or false, then the second exclamation mark gives the opposite of that (false or true).

Getting back to the challenge, it wants to apply the not-operator 'a' times and compare to the 'b' value. So something like this would work:

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

Bitwise operators always convert their operands to an integer. So, 4 >> true is the same as 4 >> 1 which will do a bit shift right by one position

(decimal) 4 = (binary) 100

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

(binary) 010 = (decimal) 2

console.log(4 >> true);

So, using true or false is a just a roundabout way to use 1 or 0.

The notNotNot function has very simple operation, overall:

  1. a%2 converts the first number into 0 for even or 1 for odd.
  2. >> b shifts right by either 0 positions for false or 1 position for true.
    • a is odd (1) and b is false = 1
      • there is zero shifts to the right, so the number remains the same.
    • a is odd (1) and b is true = 0
      • the only set bit 1 is shifted right and discarded.
    • a is even (0) and b is false = 0
      • there is zero shifts to the right, so the number remains the same.
    • a is even (0) and b is true = 0
      • the base number is 0 which doesn't have any bits set, so shifting right any amount does not change it.
  3. !!() converts the result to boolean.

With that said, the solution here is wrong, since notNotNot(2, true) will produce false - a is even and b is true. The expectation is that it will produce true since !!true = true. The same problem is present for any even number and true.

It can be easily fixed by using bitwise XOR instead of right shift:

  • a is odd (1) and b is false = 1
    • both match, so they are flipped to 0
  • a is odd (1) and b is true = 0
    • they don't match, so we get 1
  • a is even (0) and b is false = 0
    • both match, so we get 0
  • a is even (0) and b is true = 1
    • they don't match, so we get 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))

Just for completeness sake, in case you want a fully bitwise operation:

The modulo operation %2 can be changed to a bitwise AND &1 get the lowest bit. For even numbers, this would yield 0 since you'd be computing

xxx0
&
0001

which is zero. And for odd numbers the same applies but you'd get one as a result:

xxx1
&
0001

So the results of a&1 and a%2 are identical. Furthermore, even though bitwise operations convert the number to a 32-bit signed integer that doesn't matter as the parity would be preserved.

//larger than 31 bits
const largeValue = 2**31 + 1;
//larger than 32 bits
const veryLargeValue = 2**32 + 1

console.log("2**31 + 1 =", largeValue);
console.log("2**32 + 1 =", veryLargeValue);

console.log("2**31 + 1 to 32-bit signed integer =", largeValue | 0);
console.log("2**32 + 1 to 32-bit signed integer = ", veryLargeValue | 0);

const isOddModulo = number => 
  console.log(`(${number} % 2) can detect an odd number: ${(number % 2) === 1}`);

const isOddBitwise = number => 
  console.log(`(${number} & 1) can detect an odd number: ${(number & 1) === 1}`);

isOddModulo(largeValue);
isOddBitwise(largeValue);

isOddModulo(veryLargeValue);
isOddBitwise(veryLargeValue);

Tags:

Javascript