How does bitwise operation work on Booleans? - javascript

I came across this challenge on Edabit and couldn't work out this bitwise operation solution.
notNotNot = (a,b) => !!(a%2 >> b)
The challenge:
//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
I did some research that that operator:
Shifts right by pushing copies of the leftmost bit in from the left, and let the rightmost bits fall off.
That I reckon I understood (e.g. 5 >> 1 same as 0101 >> 1 which evaluates to 0010), but I can't see how that works with a boolean? I know true evaluates to 1 and false to 0.

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:
a%2 converts the first number into 0 for even or 1 for odd.
>> 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.
!!() 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);

Firstly, (a,b) => !!(a%2 >> b) does not match the results of the examples. I will break down exactly what it's doing using notNotNot(6, true) ➞ true.
Fist a%2, simply get a divide by 2 return the remainder. So we will get 0 for an even number and 1 for an odd number. a = 6 a%2 = 0 in this case.
Then 0 >> b shift 1 number off from the right because as you said true evaluates to 1. So we get 0 >> 1 = 0.
Last !!(0), is simple, and can be broken down like so, !0 = true, then !true = false.
So if we think about this as long as b is true, we will always get returned false. Let's say we have a = 5, b = true evaluating to 5%2 = 1, 1 >> 1 = 0. You can see because of the mod (%2) we will only ever have 1 or 0 (only ever have 1 digit) and true will always shift off the 1 when we have it.
A simple way to look at this problem is like an isEvenOrNot function. So a is the number we are checking and b is a boolean to check if it's even (true) or not even (false). This works because every second not added will be true.
So a solution using bitwise could be something like: (a,b) => !!(a&1 ^ b).
I will let you have the fun of breaking down why it works! :)
A little bit more into explaining how shift works with a boolean. So true as you said will be 1 and false will be 0. So as shown in your example, 0101 >> true is the same as 0101 >> 1.
I hope this helps.
I used the following as a reference for bitwise: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators

(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 For either boolean,
an even number of NOTs results in the original boolean
an odd number of NOTs results in the opposite boolean
The LSB of any number dictates whether the number is odd or even.(0 even, 1 odd)

I see that your task is:
/* Create a function where given n number of "not",
evaluate whether it's true or false.*/
I don't know why you are writing notnotnot function
for me that is not what the task asks.
So according to the task I made that function not
that accepts a number of "nots" and evaluates them.
The first way
function not(n) {
return Boolean(n - n - 1);
}
The second way using XOr(^)
function not(n) {
return Boolean(bool ^ (bool - 1));
}
The third way using Mod(%) pointed by #VLAZ
function not(n) {
return Boolean(n % 2);
}
The fourth way using bitwise And(&)
function not(n) {
return Boolean(n & 1);
}
Test
not(0)
//> false
not(1)
//> true
not(2)
//> false
not(515)
//> true

Lets analysis solution first
notNotNot(oddNumber, true) ➞ false
notNotNot(evenNumber, true) ➞ true
notNotNot(oddNumber, false) ➞ true
notNotNot(evenNumber, false) ➞ false
Now analysis the for (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 means this is not working for notNotNot(6, true) is true but current solution gives false.
We can you ^(XOR) operator to make it correct Like (a,b) => !!(a%2 ^ b)
Now analysis the for (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.
Example:
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))

Related

Why programm (massif) will be true?

So,i know that: null, " ", undefined,0, NaN will return false and all other value in JS will be true, but why:
console.log([] - 1) // -1 (it`s mean that [] = 0 (value of false?)
console.log([] - []) // 0 (wtf?),[] = 1?
if([]) console.log('true') // true
console.log(null - 1) // -1
if(null) console.log('true') // (false, no output)
Somebody, can you explain me what is going on?
This is an arithmetic expression. According to ECMAScript Language Specification, in arithmetic expression different types are converted as follows:
In expression the array ([]) is considered as object and converted to accordingly.
Full reference here.
The - operator coerces the operands to Number. if (expression) coerces the expression to Boolean.
So let's see what [] and null coerce to as Number and Boolean...
console.log(' [] as Number: ', Number([]) ); //0
console.log(' [] as Boolean:', Boolean([]) ); //true
console.log('null as Number: ', Number(null) ); //0
console.log('null as Boolean:', Boolean(null) ); //false
With that information, you get some clarity as to how each expression of yours is logging the corresponding value.
// Output | Evaluated As
console.log([] - 1) // -1 | (0 - 1)
console.log([] - []) // 0 | (0 - 0)
if([]) console.log('true') // true | ( if(true) )
console.log(null - 1) // -1 | (0 - 1)
if(null) console.log('true') // (none) | ( if(false) )

16-bit value becomes negative when bit shifting in JavaScript

I am seeing some odd behaviour when I try to bit shift a 16-bit value
0xF << 4 == 0xF0 // true
0xFF << 8 == 0xFF00 // true
0xFFF << 12 == 0xFFF000 // true
0xFFFF << 16 == 0xFFFF0000 // false
The reason the last one is true is that 0xFFFF << 16 actually gives the value -65536. Why is this happening when 0xFFFF0000 is a valid number in JavaScript
Because Javascript uses signed 32-bit integers numbers for bitwise operations.
That means, the numbers can be negative.
To have your desired output, you have to remove the sign with >>> 0.
(0xFFFF << 16) >>> 0 == 0xFFFF0000

Why does JavaScript choose the larger number in non-boolean && statements?

in JavaScript, 0 && 1 evaluates to 0, which is the lower of the two. Why, then, does 0.1 && 1 evaluate to 1, which is the higher of the two?
Similarly, why does 0 || 1 evaluate to 1, but 0.1 || 1 evaluate to 0.1
It has nothing to do with which value is larger, the operators will return the appropriate value for the spec.
In the case of && if the first parameter is false, it will be returned. Otherwise the second is returned. In your example 0.1 && 1, 0.1 is a truth-y value so 1 is returned. You could just as easily try 100000000 && 0.1 and see that 0.1 is returned. The reason that 0 && 1 returns 0 is because 0 is false-y so, per the spec, the first value gets returned.
Likewise, with || if the first parameter is true, it will be returned. Otherwise the second is returned.
You should check this out https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators.
Basically the && will take the first of the two if it is falsey otherwise it will take the second.
The opposite is true for ||.
The && and || operators do not return values based on inequalities such as < or >.
a && b works as:
if (a) {
return b;
}
else {
return a;
}
a || b works as:
if (a) {
return a;
}
else {
return b;
}
The if statements are based on the concept of "truthy" and "falsey" values, where 0, NaN, null, undefined, '', and false are all "falsey". All other values are "truthy".
0 && 1 evaluates to 0 because 0 is falsey.
0.1 && 1 evaluates to 1 because 0.1 is truthy.
There are several different things going on:
0 is bitwise false, and any number other than 0 evaluates to true, so the expression 0 && 1 evaluates to false && true, which is of course false.
1 is bitwise true, and as per above any number <> 0 also evaluates to true, so 0.1 && 1 evaluates to true && true, which is true.
Using the information above:
0 || 1 evaluates to false || true, which is true
The final example is perhaps the most interesting one, and it has to do with operator short-circuiting.
The logical or operator (||) short-circuits, or stops evaluating, as soon as it encounters a value that evaluates to true. Thus, if you are using logical or in an assignment operation, it will return the first true value in the expression.
Thus, 0.1 || 1 returns 0.1. But, if you were to evaluate 1 || 0.1, it would instead return 1.
As a related aside, the logical and operator (&&) will short-circuit as soon as it encounters a value that evaluates to false.
You're specifically discussing logical operators, which actually do not care about the numbers themselves. Your code could be rewritten as
0 && 1 - false && true
0.1 && 1 - true && true
0 || 1 - false || true
0.1 || 1 - true || true
I assume you're setting this to a variable like x or something. When you set it, the variable is being assigned as the first portion of the test that "fully" passes.
So, your cases above work like this:
The result is 0 because the test fails at 0 (0 && anything will fail).
The result is 1 because the test "fully" passes after checking the right-hand side of the equation. It checks that 0.1 is "truthy" and then checks that 1 is "truthy" and returns 1 since that was the last piece checked.
The result is 1 because the boolean logic checks 0 first, and then says "or 1". The "or 1" piece passes, so it returns 1.
The result is 0.1 because that is "truthy" and it doesn't need to check the second side of the equation.
Since this has nothing to do with the size of the numbers, just whether or not they are 0 or not 0, you can actually show this more clearly with using something like the following:
0 && -1 - false && true
0.1 && -2 - true && true
0 || -3 - false || true
0.1 || -4 - true || true

What is this line doing? arr.length >>> 0

What is this for:
arr.length >>> 0
And why should I want to use it?
It's the unsigned right shift operator. In this case (when used with 0) it ensures that arr.length is an integer, or rather, evaluates to arr.length as strict unsigned 32-bit integer value. (This means it's never NaN, never negative, and never has a decimal part.)
Examples:
'1' >>> 0: 1
1 >>> 0: 1
'' >>> 0: 0
undefined >>> 0: 0
null >>> 0: 0
1.0∙∙∙01 >>> 0: 1
Compare to:
Number('1') : 1
Number(1) : 1
Number('') : 0
Number(undefined): NaN
Number(null) : 0
Number(1.0∙∙∙01) : 1.0∙∙∙01
It’s just there to ensure that the right length is being used.
Ensures that .length is a 32-bit integer.
In most implementations, Array indices are limited to a 32-bit range (at least when working with Array.prototype methods, and the magic behaviors of .length).

Are there are any side effects of using this method to convert a string to an integer

Are there any side effects if i convert a string to a number like below..
var numb=str*1;
If I check with the below code it says this is a number..
var str="123";
str=str*1;
if(!isNaN(str))
{
alert('Hello');
}
Please let me know if there are any concerns in using this method..
When you use parseFloat, or parseInt, the conversion is less strict. 1b5 -> 1.
Using 1*number or +number to convert will result in NaN when the input is not valid number. Though unlike parseInt, floating point numbers will be parsed correctly.
Table covering all possible relevant options.
//Variables // parseInt parseFloat + 1* /1 ~~ |0 ^1 >>0 >>>0
var a = '123,',// 123 123 NaN 0 & <<0 0
b = '1.e3',// 1 1000 1000 1000 1000
c = '1.21',// 1 1.21 1.21 1 1
d = '0020',// 16 20 20 20 20
e = '0x10',// 16 0 16 16 16
f = '3e9', // 3 3000000000 <-- -1294967296 3000000000
g = '3e10',// 3 30000000000 <-- -64771072 4230196224
h = 3e25 ,// 3 3e+25 3e+25 0 0
i = '3e25',// 3 3e+25 3e+25 0 0
j = 'a123',// NaN NaN NaN 0 0
k = ' 1 ',// 1 1 1 1 1
l = ' ',// NaN NaN 0 0 0
m = '.1 ',// NaN 0.1 0.1 1 1
n = '1. ',// 1 1 1 1 1
o = '1e999',// 1 Infinity Infinity 0 0
p = '1e-999',// 1 0 0 0 0
q = false ,// NaN NaN 0 0 0
r = void 0,// NaN NaN NaN 0 0
_ = function(){return 1;}, /* Function _ used below */
s={valueOf:_},//NaN NaN 1 1 1
t={toString:_};// 1 1 1 1 1
// Intervals: (-1e+20, +1e20) (-∞,+∞) (-∞,+∞) (-2³¹,+2³¹) [0, 2³²)
// In FF9 and Chrome 17, Infinity === Math.pow(2, 1024), approx. 1.7976e+308
// In FF9 and Chrome 17, bitwise operators always return 0 after about ±1e+25
Notes on number conversion methods:
The number conversion always fail if the first character, after trimming white-space, is not a number.
parseInt returns an integer representation of the first argument. When the radix (second argument) is omitted, the radix depends on the given input.
0_ = octal (base-8), 0x_ = hexadecimal (base-16). Default: base-10.
parseInt ignores any non-digit characters, even if the argument was actually a number: See h, i.
To avoid unexpected results, always specify the radix, usually 10: parseInt(number, 10).
parseFloat is the most tolerant converter. It always interpret input as base-10, regardless of the prefix (unlike parseInt). For the exact parsing rules, see here.
The following methods will always fail to return a meaningful value if the string contains any non-number characters. (valid examples: 1.e+0 .1e-1)
+n, 1*n, n*1, n/1 and Number(n) are equivalent.
~~n, 0|n, n|0, n^1, 1^n, n&n, n<<0 and n>>0 are equivalent. These are signed bitwise operations, and will always return a numeric value (zero instead of NaN).
n>>>0 is also a bitwise operation, but does not reserve a sign bit. Consequently, only positive numbers can be represented, and the upper bound is 232 instead of 231.
When passed an object, parseFloat and parseInt will only look at the .toString() method. The other methods first look for .valueOf(), then .toString(). See q - t.
NaN, "Not A Number":typeof NaN === 'number'
NaN !== NaN. Because of this awkwardness, use isNaN() to check whether a value is NaN.
When to use which method?
parseFloat( x ) when you want to get as much numeric results as possible (for a given string).
parseFloat( (x+'').replace(/^[^0-9.-]+/,'') ) when you want even more numeric results.
parseInt( x, 10 ) if you want to get integers.
+x, 1*x .. if you're only concerned about getting true numeric values of a object, rejecting any invalid numbers (as NaN).
~~, 0| .. if you want to always get a numeric result (zero for invalid).
>>>0 if negative numbers do not exists.
The last two methods have a limited range. Have a look at the footer of the table.
The shortest way to test whether a given parameter is a real number is explained at this answer:
function isNumber(n) {
return typeof n == 'number' && !isNaN(n - n);
}

Categories