Related
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))
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
I am excited to find the following Javascript behavior:
$ node
> false/true
0
> false/false
NaN
> false/true
0
> true/true
1
> true/false
Infinity
Why is this happening?
My first approach is that Javascript converts false to 0 and true to 1.
Is this correct? A reference from the documentation would be great.
You're absolutely right, the ToNumber abstract operation converts true to 1 and false to positive 0.
The specification says:
Boolean
The result is 1 if the argument is true. The result is +0 if the
argument is false.
> 0/0
NaN
> 1/0
Infinity
> 0/1
0
> 1/1
1
They are all converted to numbers.
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);
}
I was checking out an online game physics library today and came across the ~~ operator. I know a single ~ is a bitwise NOT, would that make ~~ a NOT of a NOT, which would give back the same value, wouldn't it?
It removes everything after the decimal point because the bitwise operators implicitly convert their operands to signed 32-bit integers. This works whether the operands are (floating-point) numbers or strings, and the result is a number.
In other words, it yields:
function(x) {
if(x < 0) return Math.ceil(x);
else return Math.floor(x);
}
only if x is between -(231) and 231 - 1. Otherwise, overflow will occur and the number will "wrap around".
This may be considered useful to convert a function's string argument to a number, but both because of the possibility of overflow and that it is incorrect for use with non-integers, I would not use it that way except for "code golf" (i.e. pointlessly trimming bytes off the source code of your program at the expense of readability and robustness). I would use +x or Number(x) instead.
How this is the NOT of the NOT
The number -43.2, for example is:
-43.210 = 111111111111111111111111110101012
as a signed (two's complement) 32-bit binary number. (JavaScript ignores what is after the decimal point.) Inverting the bits gives:
NOT -4310 = 000000000000000000000000001010102 = 4210
Inverting again gives:
NOT 4210 = 111111111111111111111111110101012 = -4310
This differs from Math.floor(-43.2) in that negative numbers are rounded toward zero, not away from it. (The floor function, which would equal -44, always rounds down to the next lower integer, regardless of whether the number is positive or negative.)
The first ~ operator forces the operand to an integer (possibly after coercing the value to a string or a boolean), then inverts the lowest 31 bits. Officially ECMAScript numbers are all floating-point, but some numbers are implemented as 31-bit integers in the SpiderMonkey engine.
You can use it to turn a 1-element array into an integer. Floating-points are converted according to the C rule, ie. truncation of the fractional part.
The second ~ operator then inverts the bits back, so you know that you will have an integer. This is not the same as coercing a value to boolean in a condition statement, because an empty object {} evaluates to true, whereas ~~{} evaluates to false.
js>~~"yes"
0
js>~~3
3
js>~~"yes"
0
js>~~false
0
js>~~""
0
js>~~true
1
js>~~"3"
3
js>~~{}
0
js>~~{a:2}
0
js>~~[2]
2
js>~~[2,3]
0
js>~~{toString: function() {return 4}}
4
js>~~NaN
0
js>~~[4.5]
4
js>~~5.6
5
js>~~-5.6
-5
In ECMAScript 6, the equivalent of ~~ is Math.trunc:
Returns the integral part of a number by removing any fractional digits. It does not round any numbers.
Math.trunc(13.37) // 13
Math.trunc(42.84) // 42
Math.trunc(0.123) // 0
Math.trunc(-0.123) // -0
Math.trunc("-1.123")// -1
Math.trunc(NaN) // NaN
Math.trunc("foo") // NaN
Math.trunc() // NaN
The polyfill:
function trunc(x) {
return x < 0 ? Math.ceil(x) : Math.floor(x);
}
The ~ seems to do -(N+1). So ~2 == -(2 + 1) == -3 If you do it again on -3 it turns it back: ~-3 == -(-3 + 1) == 2 It probably just converts a string to a number in a round-about way.
See this thread: http://www.sitepoint.com/forums/showthread.php?t=663275
Also, more detailed info is available here: http://dreaminginjavascript.wordpress.com/2008/07/04/28/
Given ~N is -(N+1), ~~N is then -(-(N+1) + 1). Which, evidently, leads to a neat trick.
Just a bit of a warning. The other answers here got me into some trouble.
The intent is to remove anything after the decimal point of a floating point number, but it has some corner cases that make it a bug hazard. I'd recommend avoiding ~~.
First, ~~ doesn't work on very large numbers.
~~1000000000000 == -727279968
As an alternative, use Math.trunc() (as Gajus mentioned, Math.trunc() returns the integer part of a floating point number but is only available in ECMAScript 6 compliant JavaScript). You can always make your own Math.trunc() for non-ECMAScript-6 environments by doing this:
if(!Math.trunc){
Math.trunc = function(value){
return Math.sign(value) * Math.floor(Math.abs(value));
}
}
I wrote a blog post on this for reference: http://bitlords.blogspot.com/2016/08/the-double-tilde-x-technique-in.html
Converting Strings to Numbers
console.log(~~-1); // -1
console.log(~~0); // 0
console.log(~~1); // 1
console.log(~~"-1"); // -1
console.log(~~"0"); // 0
console.log(~~"1"); // 1
console.log(~~true); // 1
console.log(~~false); // 0
~-1 is 0
if (~someStr.indexOf("a")) {
// Found it
} else {
// Not Found
}
source
~~ can be used as a shorthand for Math.trunc()
~~8.29 // output 8
Math.trunc(8.29) // output 8
Here is an example of how this operator can be used efficiently, where it makes sense to use it:
leftOffset = -(~~$('html').css('padding-left').replace('px', '') + ~~$('body').css('margin-left').replace('px', '')),
Source:
See section Interacting with points
Tilde(~) has an algorihm -(N+1)
For examle:
~0 = -(0+1) = -1
~5 = -(5+1) = -6
~-7 = -(-7+1) = 6
Double tilde is -(-(N+1)+1)
For example:
~~5 = -(-(5+1)+1) = 5
~~-3 = -(-(-3+1)+1) = -3
Triple tilde is -(-(-(N+1)+1)+1)
For example:
~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4
Same as Math.abs(Math.trunc(-0.123)) if you want to make sure the - is also removed.
In addition to truncating real numbers, ~~ can also be used as an operator for updating counters in an object. The ~~ applied to an undefined object property will resolve to zero, and will resolve to the same integer if that counter property already exists, which you then increment.
let words=["abc", "a", "b", "b", "bc", "a", "b"];
let wordCounts={};
words.forEach( word => wordCounts[word] = ~~wordCounts[word] + 1 );
console.log("b count == " + wordCounts["b"]); // 3
The following two assignments are equivalent.
wordCounts[word] = (wordCounts[word] ? wordCounts[word] : 0) + 1;
wordCounts[word] = ~~wordCounts[word] + 1;