Unambiguous increment and adding results in error - javascript

When playing around with JavaScript syntax it struck me that the following code will throw an error in SpiderMonkey and V8 engines:
var a = 1, b = 1;
a++++b;
This to me is strange, since the following works perfectly fine:
var a = 1, b = 1;
a+++b; // = 2; (Add a and b, then increase a)
// now a == 2 and b == 1
a+++-b; // = 1; (add a and -b, then increase a)
// now a == 3 and b == 1
In addition, the following would be nonsensical code:
var a = 1, b = 1;
a++ ++b; // throws an error
My argument is now that if a+++b is equivalent to a++ + b, and not to a+ ++b, and a+++-b is equivalent to a++ + -b, then a++++b can only be interpreted as a++ + +b in order for it to be valid JavaScript code.
Instead, the engines insist that a++++b is interpreted as a++ ++b, by operator precedence.
This to me is in contrast with the logic that the engines implements using the / symbol, as explained here, to distinguish between division and regular expressions. An example
var e = 30, f = 3, g = 2;
e/f/g; // == 5
e
/f/g; // == 5
/f/g; // is equivalent to new RegExp("f","g")
Here the argument is that because /f/g does not make sense as division in the last line, it is interpreted as a regular expression.
Obviously the / symbol gets a special treatment, in order to distinguish between division and regular expressions. But then why do ++ and -- not get a special treatment as well? (That is, outside operator precedence)
A second question is why operator precedence is not called only when the code is has multiple valid interpretations.

In the code a++++b you have two distinct statements: a++ and ++b with nothing to combine them. The + operator in the context of a++ + +b is actually a type converter (meant for turning strings into numbers) and has a different order of precedence which follows the others in the list.

Related

Bitwise OR ( | ) and Bitwise Operator ( ~ ) - Javascript

The challenge: Given integers N and K (where 2 <= K <= N), find the highest value of A & B (i.e. A bitwise-AND B) such that 0 <= A < B <= N and (A & B) < K.
I've made my code and it runs perfect with visible cases but it fails with the hidden cases.
My Code:
function bitwiseAnd(N, K) {
// Write your code here
let arr = []
N = parseInt(N,10)
K = parseInt(K,10)
for(let a=1; a<N; a++){
for(let b=a+1; b<=N ; b++){
if(K>=0 && parseInt(a&b,10) < K && parseInt(a&b,10)>=0) arr.push(parseInt(a&b,10))
}
}
return Math.max(...arr)
}
i searched for a solution and i found this one.
Solution:
function bitwiseAnd(N, K) {
// Write your code here
var n = parseInt(N);
var k = parseInt(K);
var a = k - 1;
var b = (~a) & -(~a);
if ( (a | b) > n )
return(a - 1);
else
return(a);
}
However the solution's code is working good with all hidden test, i cannot understand how it works, as i'm not familiar with Bitwise operators.
is there any chance to get an explanation of this operators and how to use ?
Thanks in advance.
Here is a variant of your code that works:
function bitwiseAnd(N, K) {
let r = 0;
for(let a=1; a<N; a++) {
for(let b=a+1; b<=N; b++) {
if((a&b) < K) r = Math.max(r, a&b)
}
}
return r
}
console.log(bitwiseAnd(5,2)) // 1
console.log(bitwiseAnd(8,5)) // 4
console.log(bitwiseAnd(2,2)) // 0
I've removed unnecessary parseInts and result checks. However, the only thing that was actually wrong with your code was the line Math.max(...arr).
The problem with that line is that it is not passing a reference to arr to the Math.max method. Instead, it is actually including all members of arr as arguments which will appear on the Javascript call stack. Normally, this would be fine. However, if you have hundreds of thousands of values in the array, the maximum call stack size will be exceeded and your code will fail to execute. This is why a hidden test case, which must have resulted in huge numbers of array members, caused hackerrank to reject your solution.
You've also posted a very interesting solution which does not use loops at all.
I've cleaned it up a little, and included it below:
function bitwiseAnd(n, k) {
let a = k-1
return (a | ~a & a+1) <= n ? a : a-1
}
console.log(bitwiseAnd(5,2)) // 1
console.log(bitwiseAnd(8,5)) // 4
console.log(bitwiseAnd(2,2)) // 0
Note that the original code said & -(~a) instead of & a+1. The Two's complement method of negating a number is to flip all bits and add one to the result. Since the bitwise not ~ also means to flip all bits, the original code flips all bits, flips all bits again, and then adds one. This is therefore an obfuscation of simply doing a+1.
Here is an explanation of the thinking that must be behind that code:
Since the result of A & B must be less than K, the maximum number that might be the result will be K-1.
When we do the bitwise A & B, the result can only switch certain bits off, and cannot switch any bits on. Since A must be a smaller number than B, and since we can only switch bits of A off, the result of A & B thus cannot exceed the value of A.
Combining the two conclusions above, we can conclude:
The choice of A cannot exceed K-1 if our choice of B will preserve all bits of A.
So, let's see if we can set A to K-1 and find a value of B which will preserve all bits in A.
The first value greater than A that will preserve all bits of A will be the result of setting the least significant bit that is currently unset.
For example, if A = 101, the next value of B that will preserve all bits of A after doing A & B is 111.
In order to locate the position of the least significant unset bit, we can do ~A & A+1. For the example where A is 101, ~A & A+1 is 010. Essentially, ~A & A+1, no matter what the value of A, will always return a binary sequence containing exactly one set bit.
The reason this works is that ~A acts as a mask that will only allow the result of ~A & A+1 to contain bits which were unset in A. When we do A+1, the first bit that will be set for the first time in A will be the least significant unset bit, and no other bits will be set for the first time.
For example: if A = 101, ~A = 010, A+1 = 110, and so ~A & A+1 = 010 & 110 = 010. That 1 in the answer is the position of the least significant unset bit in A.
If we do a bitwise OR, we can use this result to calculate the first higher value of B which will preserve all bits of A. Thus B = A | ~A & A+1. Therefore, we can see in the runnable code snippet above that if we find that (a | ~a & a+1) <= n, we know that the value of a = k-1 will work and we can return this as the answer.
But, what if that value of B that exceeds N? We will need to find the next-best answer.
Since we tried A = K-1, and since the question states K <= N, this means A must have been an odd number (i.e. the least significant bit was set). This is because if A was even, we'd have attempted the value B = A + 1, and B could not have exceeded N since K <= N and A = K-1.
So, since our earlier attempt failed when we tried A = K-1, we know we can't go higher than A to find a value of B that works when A = K-1.
But, if we set A = K-2, and since we know K-1 was odd, this means K-2 is even. This means that we can have A = K-2 and B = K-1, and A & B = K-2. The result of the function is therefore K-2.
The code could therefore perhaps be more clearly written as:
function bitwiseAnd(n, k) {
let a = k-1
return (a | ~a & a+1) <= n ? k-1 : k-2
}
console.log(bitwiseAnd(5,2)) // 1
console.log(bitwiseAnd(8,5)) // 4
console.log(bitwiseAnd(2,2)) // 0
The bottom line is that we don't need any loops, because there is always an answer where A = K-1 and B is more than one higher than A, or where A = K-2 and B = K-1.
But, there is an improvement we can make...
So far, we've explained the thinking behind the solution you posted. That solution, however, is more complicated than it needs to be.
If we want to take A and set the least-significant unset bit, we can simply do A | A+1.
This means a simpler solution would be:
function bitwiseAnd(n, k) {
let a = k-1
return (a | a+1) <= n ? k-1 : k-2
}
console.log(bitwiseAnd(5,2)) // 1
console.log(bitwiseAnd(8,5)) // 4
console.log(bitwiseAnd(2,2)) // 0
And, if we really want to code-golf the solution, we can substitute out the variable a, and take advantage of Javascript coercing true/false to 1/0 and do:
function bitwiseAnd(n, k) {
return --k-((k++|k)>n)
}
console.log(bitwiseAnd(5,2)) // 1
console.log(bitwiseAnd(8,5)) // 4
console.log(bitwiseAnd(2,2)) // 0

Javascript: Weird behaviour with += operator

I know the title is somewhat vague, but I'm not sure how to really explain this. So, in code
var a= 2, b=3;
a+=b;
//5
This is pretty basic javascript. Now I want to check if the result is larger than a certain number
var a= 2, b=3, c=4;
(a+=b) >= c;
//true
However, if I forget to add the parenthesis, I don't understand where the result could possible come from
var a= 2, b=3, c=4;
a += b >= c;
//2
I tried reading some stuff about order of operations and whatnot, but I still can't understand how that code can possibly output "2"
Because
a += b >= c;
is
a += (b >= c);
which is (in your case)
a += (false);
which ends up being
a += 0;
which is a.
The right-hand side of all of the assignment operators is evaluated before anything is done with the result. So b >= c is evaluated, giving us false, which is coerced to 0 when you try to treat it as a number with a +=.

Javascript syntax: equal signs and commas

I really didn't know what to call this question, neither what I could google for. I'm trying to understand the source code for the D3.js library and I've encountered two functions that I simply can't understand, due to the syntax that is new to me.
The first one is the number interpolator:
function d3_interpolateNumber(a, b) {
b -= a = +a;
return function(t) { return a + b * t; };
}
What's going on on the second line here? We're subtracting the value of b from the value of a and then...uhm, you lost me. How does this syntax work?
The other thing that confuses me, that I've seen in other places as well, is where the right-hand assignment of a variable consists of several variables separated by commas. As in:
var i = d3.interpolators.length, f;
What does this mean? These snippets are taken from https://github.com/mbostock/d3/blob/master/src/interpolate/number.js and
https://github.com/mbostock/d3/blob/master/src/interpolate/interpolate.js
The first line you're asking about is just two assignments. It's equivalent to this:
a = +a;
b -= a;
The +a is using the unary plus operator to convert a string to a number. So we are converting a to a number and then subtracting that number from b (and reassigning the new value to b).
The second bit of syntax you're asking about is simply a list of variable declarations. For example:
var a, b, c; // Declares 3 variables, all initialised to undefined
That's equivalent to this:
var a;
var b;
var c;
In your example, one of the declarations in the list also includes an assignment. Any number of them can, so this is valid too:
var a, b = 1, c = true, d;
An assignment is also an expression, which returns the value that is assigned. So this:
b -= a = +a;
is the same as:
b -= (a = +a);
or:
a = +a;
b -= a;
If the right hand side would really be values separated by comma, i.e:
var i = (d3.interpolators.length, f);
then the comma operator returns the value of the last operand, so it would be the same as:
d3.interpolators.length;
var i = f;
However, without the parentheses the comma is a separator between declared variables, not the comma operator, so it's the same as:
var i = d3.interpolators.length;
var f;
The second line is
b -= (a = +a);
Which means:
set a to +a (conversion to a number). Return this value outside of the parentheses.
Whatever value was returned, subtract it from b.
or
a=+a //converts a to an int
b-=a // or b=b-a
Remember, assignments return their value. So, alert(a=1) will alert 1.
On the other hand,
var i = d3.interpolators.length, f;
splits to:
var i = d3.interpolators.length;
var f;
This is just basically a way of saying "var applie to the following comma separated list"

`x = y, z` comma assignment in JavaScript [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript syntax: what comma means?
I came across the code while reading this article (do a Ctrl+F search for Andre Breton):
//function returning array of `umbrella` fibonacci numbers
function Colette(umbrella) {
var staircase = 0, galleons = 0, brigantines = 1, armada = [galleons, brigantines], bassoon;
Array.prototype.embrace = [].push;
while(2 + staircase++ < umbrella) {
bassoon = galleons + brigantines;
armada.embrace(brigantines = (galleons = brigantines, bassoon));
}
return armada;
}
What does the x = (y = x, z) construct mean? Or more specifically, what does the y = x, z mean? I'm calling it comma assignment because it looks like assignment and has a comma.
In Python, it meant tuple unpacking (or packing in this case). Is it the same case here?
This is the comma operator.
The comma operator evaluates both of its operands (from left to right)
and returns the value of the second operand.
The resultant value when a,b,c,...,n is evaluated will always be the
value of the rightmost expression, however all expressions in the
chain are still evaluated (from left to right).
So in your case, the assignations would still be evaluated, but the final value would be bassoon.
Result:
galleons = brigantines
brigantines = bassoon
armada.embrace(basson)
More information: Javascript "tuple" notation: what is its point?
var syntax allows multiple assignment, so when you see the following, you're declaring multiple variables using one var statement.
var a, b, c;
Note that this syntax is not the comma operator.
The , can be used as the comma operator. It simply evaluates a series of expressions. So when you see the following syntax, you are seeing a series of expressions being evaluated, and the return value of the last one being returned.
x = (y = x, z)
Within the parens, x is assigned to y, then z is evaluated and returned from the () and assigned to x.
I'd suggest that this syntax is unclear and offers little benefit.
The comma operand evaluates all of its operands and returns the last one. It makes no difference in this case if we had used
x = (y = x, z);
or
y = x;
x = z;
It's there to take away that line of code.

Javascript - Ternary Operator with Multiple Statements

Is this valid JavaScript? I saw an example where someone used commas in the ternary operator conditions, and it was marked as an error in my editor, and the example didn't run in Chrome. However, it did run in Firefox. Once I converted all the ternary statements to if/else statements, the app ran on Chrome.
a!==b ? (a=1, b=2) : (a=2, b=1)
Edit:
This is the actual statement in the code:
a!==0?b<0?(h=b/a,e=h-1,f=-2*b+2*a*e,i=-2*b+2*a*h,d=2*h*a-2*b-2*a):(h=b/a,e=h+1,f=2*b-2*a*e,i=2*b-2*a*h,d=-2*h*a+2*b):d=h=e=f=i=0
Yes, it's valid, and it runs fine in Chrome:
var a, b, c;
a = 6;
b = 7;
c = a !== b ? (a = 1, b = 2) : (a = 2, b = 1);
console.log("a = " + a);
console.log("b = " + b);
console.log("c = " + c);
I'm not saying it's a remotely good idea in code humans are meant to read. :-) I expect jamietre is correct in the comments when he/she says it looks like the result of minification.
The comma operator is a binary operator (an operator accepting two operands). It evaluates its left-hand operand (thus causing any side-effects it has, such as assignment), throws that result away, then evalutes its right-hand operand (thus causing its side-effects if any) and takes that result as its result value. If you have multiple comma operators in a row, the overall expression is evaluated in order, left-to-right, with the final result being the value resulting from the right-most operand evaluation.
And of course, you know the conditional operator (a ternary operator — one accepting three operands) is used to pick one of two sub-expressions to evaluate, on the basis of an initial expression.
So that line is very...expressive...what with a total of seven* different expressions inside it.
So in that example, the result of the overall expression is 2 if a !== b initially, or 1 if a === b initially, with the side-effects of setting a and b.
It's the side effects that make it, in my view, a questionable choice. And of course, there's no reason to use the comma operator if the left-hand operand doesn't have side effects.
* Yes, seven of 'em packed into that overall ternary:
a !== b
the first comma expression
a = 1
b = 2
the second comma expression
a = 2
b = 1
Re your edit with the actual statement, that one works too:
function test(a) {
var b = 7,
d = 1,
e = 2,
f = 3,
g = 4,
h = 5,
i = 6;
a!==0?b<0?(h=b/a,e=h-1,f=-2*b+2*a*e,i=-2*b+2*a*h,d=2*h*a-2*b-2*a):(h=b/a,e=h+1,f=2*b-2*a*e,i=2*b-2*a*h,d=-2*h*a+2*b):d=h=e=f=i=0;
console.log("a = " + a);
console.log("b = " + b);
console.log("d = " + d);
console.log("e = " + e);
console.log("f = " + f);
console.log("g = " + g);
console.log("h = " + h);
console.log("i = " + i);
}
test(0);
test(1);
.as-console-wrapper {
max-height: 100% !important;
}
But wow, I hope this is minified, because if a person wrote that, they must really have a thing against anyone who's supposed to maintain it later... ;-)
Yes:
a=1;
b=2;
a!==b ? (a=1, b=2) : (a=2, b=1)
console.log(a); // 1
console.log(b); // 2
and:
a=1;
b=2;
a===b ? (a=1, b=2) : (a=2, b=1)
console.log(a); // 2
console.log(b); // 1
As you can analyze, changing the equality operator reacts correctly to our test if you look at the results.
Or you can do this :
b = a!==b ? (a=1,2) : (a=2,1);
Read here about comma operator.
The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
Expanding on this topic with ES6 code example. If you're using one side of the TRUE : FALSE argument to iterate thru all cases in one IF, it makes sense to separate the code as if it's a switch | case statement.
Nesting implies that there is branching logic, while it is logically nested, writing nested IF's complicates what we're doing in my example. Like a lawyer over explaining a problem to a jury. IMO, you want to explain the point in it's simplest form. For instance, I find this example the most logical way of expressing nested ifs where the TRUE is executed. The final false is your last else {}
choreDoor is either 0,1 or 2:
choreDoor === 0 ?
(openDoor1 = botDoorPath,
openDoor2 = beachDoorPath,
openDoor3 = spaceDoorPath)
: choreDoor === 1 ?
(openDoor2 = botDoorPath,
openDoor1 = beachDoorPath,
openDoor3 = spaceDoorPath)
: choreDoor === 2 ?
(openDoor3 = botDoorPath,
openDoor1 = beachDoorPath,
openDoor2 = spaceDoorPath)
: false;
If you don't want to use the Comma operator (,) then you can use nested Conditional (ternary) operators instead.
var a = 6;
var b = 7;
var c = (a !== b)? // true
((a = 1 || 1===1)? (b = 2) : null) // will first run a=1, then b=2
: ((a = 0 || 1===1)? (b = 0) : null);
console.log("a = " + a);
console.log("b = " + b);
console.log("c = " + c);

Categories

Resources