I just tested the following code:
int x = 90;
x = x - (x = x - 1);
System.out.print(x);
It prints 1.
As far as I understand, things go in the following order:
x - 1 is computed and stored to a temporary variable in memory.
x is assigned the result from the temporary variable from item 1.
Then x - the new value of x is calculated.
The result is assigned to x;
I don't understand why x from which we subtract the result of item 2 still has initial value after item 2. What am I missing?
From https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
All binary operators except for the assignment operators are evaluated from left to right; assignment operators are evaluated right to left.
You are doing 90 - (90 - 1) => 1
It's important to not confuse precedence with order of evaluation. They are related but not the same.
EDIT
As #ruakh points out, the JLS spec put it differently to the tutorial above.
http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.7.
The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.
If the operator is a compound-assignment operator (§15.26.2), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied binary operation.
If evaluation of the left-hand operand of a binary operator completes abruptly, no part of the right-hand operand appears to have been evaluated.
Rather than say the assignment is evaluated right to left, it treats assignment as first a store of the variable to be updated, then an evaluation of the value and finally an assignment.
We start with:
int x = 90;
x = x - (x = x - 1);
The first assignment operator = has low precedence, so the right side is evaluated first.
The right side of x = x - (x = x - 1) is x - b where b is (x = x - 1)
This right side is evaluated left to right, so it becomes 90 - b
Then b, which is (x = x - 1), is evaluated. Once again the assignment operator has lowest precedence, so it becomes (x = 90 - 1) or (x = 89)
Substituting back, we have 90 - (x = 89) which is 90 - 89 which is 1. Finally, the first assignment operator is evaluated and x becomes 1. You'll notice that the other assignment operator (x = 89) had no effect on the overall operation.
int x = 90;
x = x - (x = x - 1);
System.out.print(x);`
Here
x = 90 Goes in two section in your code.
First x=90 - , Second (x=90-1);
Then x=90 - , x = 89
Then x= 90 - 89
System.out.Print(x);
that is x=1;
Related
I'm trying to swap two ints - x and y in the example, and do it in one line without a library function.
So I started with this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
y ^= x;
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
The output was 4, 3, 7, 3, 7, 4, 3, 4 as expected. All good so far.
Next up was this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
y ^= (x ^= y);
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
The output was 4, 3, 7, 4, 3, 4 as expected once again. Still good so far.
Then finally this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
x ^= (y ^= (x ^= y));
System.out.println(x);
System.out.println(y);
At this stage the output became 4, 3, 0, 4. Now I know that the 0 is a result of 4 ^ 4 because the x assignment wasn't complete at that time - why is this happening? Why doesn't the x ^= y actually assign 7 to the x variable so that it becomes 7 ^ 4 for the last assignment?
Let's try to expand your last expression.
It evaluates to,
x = x^(y = y^ (x = x^y));
Note that expressions are evaluated from left to right,
it becomes,
x = 4 ^ (y = 3 ^ (x = 4 ^ 3));
Now, the problem has become obvious. Right?
Edit:
To clear come confusion, let me try to explain what I mean by evaluating from left to right.
int i = 1;
s = i + (i = 2) + i;
Now, the expression will evaluate to,
s = 1 + 2 + 2;
Notice that i on the left of assignment was 1, but on the right of assignment (and on the assigment) was evaluated to 2, because the evaluation is from left to right, when it came to the 2nd and 3rd part of the expression, is value was 2.
The order of evaluation is defined in chapter 15 of the JLS. Item 15.7.1 says:
If the operator is a compound-assignment operator (§15.26.2), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied binary operation.
To explain further, they have two examples of computations that involve assignments. Here the assignment is on the left hand of the operator:
int i = 2;
int j = (i=3) * i;
System.out.println(j);
And they specifically say that the result is 9 and is not allowed to be 6. That is, the (i=3) is both calculated as 3 and i is assigned 3 before being multiplied with itself.
But in the second example:
int a = 9;
a += (a = 3); // first example
System.out.println(a);
int b = 9;
b = b + (b = 3); // second example
System.out.println(b);
The JLS specifies that both prints should produce 12, and are not allowed to produce 6. That is, because the assignment to b is on the right side, the value of the left b (or the implicit left a in the += operation), the value before that assignment is fetched and saved first, and only then the operation inside the parentheses is performed.
Internally, expressions are broken down into JVM operations that push and pop values onto an "operand stack". If you think about it like that - that in b = b + (b=3) The value of b is first pushed onto the operand stack, then the (b=3) is performed and its value is then added to the value popped from the stack (old value of b), it will make sense. At this point, the left hand b just stands for "What the value of b was when it was pushed on the stack" and not for the "current value of b".
Lets divide and compute.
The innermost parenthesis executes first and after all the parenthesis resolved, then the expression executes from left to right.
x ^= (y ^= (x ^= y)); // initial statement
x = x^(y = y^ (x = x^y)); //equals to
() have the highest precedence
x = x^(y = y^ (x = 3^4)); // first highest precedence ()
x = x^(y = y ^ (x = 7)); // still the first x is 3
x = 4 ^(y = 3 ^ (x = 7)); // now 3 ^ 7 =4
x = 4 ^ 4; // now 3 ^ 7 =4
x= 0;
Consider the following pseudo-code:
int x = 10;
int y = 10;
x = x + x++;
y = y++ + y;
print(x); // 20
print(y); // 21
C-like programming languages like C# or Java say that increment has higher precedence, than + operator. So it should be 21 in both cases.
Why does it print two different results?
Remember we work from left to right.
Let's deal with x first then y.
x
x = x + x++;
We are going from left to right...
x = 10 + (10++)
Note: As we go from left to right the post increment operator on x on the far right has no effect on the x which appears first on the RHS.
x = 20
y
y = y++ + y;
y = 10++ + 11;
Again we go from left to right, the increment operator post increments y from 10 to 11, hence the y on the far right becomes 11, thus yielding (10 + 11) = 21.
When y++ + y is evaluated, y++ is evaluated before y. So the left hand side is evaluated to 10, and the right hand side will be evaluated to 11 due to the previous incrementation.
When x + x++ is evaluated, x is evaluated before x++. So both sides will be evaluated to 10, then x will be evaluated to 11 just before the = operand will evaluate x to 20.
I believe the + operator has higher precedence than ++, so the + operator is evaluated first, but in order to evaluate it - it must evaluate the left and right operators of it.
In the second example the left operator is evaluated first so y increments before the right hand is evaluated.
In the Precedence and Order of Evaluation documentation, you can see that + is above += which is basically what ++ is. Above the + is the prefix ++ which is not to be confused with the postfix ++.
I'm trying to swap two ints - x and y in the example, and do it in one line without a library function.
So I started with this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
y ^= x;
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
The output was 4, 3, 7, 3, 7, 4, 3, 4 as expected. All good so far.
Next up was this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
y ^= (x ^= y);
System.out.println(x);
System.out.println(y);
x ^= y;
System.out.println(x);
System.out.println(y);
The output was 4, 3, 7, 4, 3, 4 as expected once again. Still good so far.
Then finally this:
int x = 4;
int y = 3;
System.out.println(x);
System.out.println(y);
x ^= (y ^= (x ^= y));
System.out.println(x);
System.out.println(y);
At this stage the output became 4, 3, 0, 4. Now I know that the 0 is a result of 4 ^ 4 because the x assignment wasn't complete at that time - why is this happening? Why doesn't the x ^= y actually assign 7 to the x variable so that it becomes 7 ^ 4 for the last assignment?
Let's try to expand your last expression.
It evaluates to,
x = x^(y = y^ (x = x^y));
Note that expressions are evaluated from left to right,
it becomes,
x = 4 ^ (y = 3 ^ (x = 4 ^ 3));
Now, the problem has become obvious. Right?
Edit:
To clear come confusion, let me try to explain what I mean by evaluating from left to right.
int i = 1;
s = i + (i = 2) + i;
Now, the expression will evaluate to,
s = 1 + 2 + 2;
Notice that i on the left of assignment was 1, but on the right of assignment (and on the assigment) was evaluated to 2, because the evaluation is from left to right, when it came to the 2nd and 3rd part of the expression, is value was 2.
The order of evaluation is defined in chapter 15 of the JLS. Item 15.7.1 says:
If the operator is a compound-assignment operator (§15.26.2), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied binary operation.
To explain further, they have two examples of computations that involve assignments. Here the assignment is on the left hand of the operator:
int i = 2;
int j = (i=3) * i;
System.out.println(j);
And they specifically say that the result is 9 and is not allowed to be 6. That is, the (i=3) is both calculated as 3 and i is assigned 3 before being multiplied with itself.
But in the second example:
int a = 9;
a += (a = 3); // first example
System.out.println(a);
int b = 9;
b = b + (b = 3); // second example
System.out.println(b);
The JLS specifies that both prints should produce 12, and are not allowed to produce 6. That is, because the assignment to b is on the right side, the value of the left b (or the implicit left a in the += operation), the value before that assignment is fetched and saved first, and only then the operation inside the parentheses is performed.
Internally, expressions are broken down into JVM operations that push and pop values onto an "operand stack". If you think about it like that - that in b = b + (b=3) The value of b is first pushed onto the operand stack, then the (b=3) is performed and its value is then added to the value popped from the stack (old value of b), it will make sense. At this point, the left hand b just stands for "What the value of b was when it was pushed on the stack" and not for the "current value of b".
Lets divide and compute.
The innermost parenthesis executes first and after all the parenthesis resolved, then the expression executes from left to right.
x ^= (y ^= (x ^= y)); // initial statement
x = x^(y = y^ (x = x^y)); //equals to
() have the highest precedence
x = x^(y = y^ (x = 3^4)); // first highest precedence ()
x = x^(y = y ^ (x = 7)); // still the first x is 3
x = 4 ^(y = 3 ^ (x = 7)); // now 3 ^ 7 =4
x = 4 ^ 4; // now 3 ^ 7 =4
x= 0;
I don`t understand how Java is progressing this arithmetic expression
int x = 1;
int y = 1;
x += y += x += y;
System.out.println("x=" + x + " y=" + y);
With Java I get x = 4 and y = 3. But in C, Perl, Php I get x=5 and y = 3
On the paper I also get x = 5 and y = 3
This is the nasty part, obviously:
x += y += x += y;
This is executed as:
int originalX = x; // Used later
x = x + y; // Right-most x += y
y = y + x; // Result of "x += y" is the value stored in x
x = originalX + y; // Result of "y += x" is the value stored in y
So:
x y
(Start) 1 1
x = x + y 2 1
y = y + x 2 3
x = originalX + y 4 3
The important part is the use of originalX here. The compound assignment is treated as:
x = x + y
and the first operand of + is evaluated before the second operand... which is why it takes the original value of x, not the "latest" one.
From JLS section 15.16.2:
If the left-hand operand expression is not an array access expression, then:
First, the left-hand operand is evaluated to produce a variable. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.
Otherwise, the value of the left-hand operand is saved and then the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.
When in doubt, consult the language specification - and never assume that just because two languages behave differently, one of them is "wrong". So long as the actual behaviour matches the specified behaviour for each language, all is well - but it does mean you need to understand the behaviour of each language you work with, of course.
That said, you should clearly avoid horrible code like this in the first place.
it starts from right to left
1. x += y gives x = 2, y = 1
2. y += ( x +=y ) gives x = 2, y = 3
3. x += ( y += x += y ) gives x = 4, y = 3
so, it's all consistent
I'm stuying this code and I don't understand what this line does: [(y << 3) + x]
for (int y = 0; y <= 7; ++y) {
for (int x = 0; x <= 7; ++x) {
final String pieceCode = pieceCodes[(y << 3) + x];
if (pieceCode.length() != 2) throw new IllegalArgumentException();
if (!pieceCode.equals("--")) {
pieces[((7 - y) << 3) + x] = CheckersPiece.valueOf(pieceCode.charAt(0), pieceCode.charAt(1));
}
}
}
It's an obfuscated way of multiplying by 8. Thus, (y << 3) + x is equal to 8 * y + x.
The reason that y << 3 is equivalent to multiplying by 8 is because << is the left-shift operator: it shifts all the bits of y left by one position. In the same way that if you take a base-10 number and shift left by one position you have multiplication by 10, shifting left in base-2 is equivalent to multiplying by 2. Therefore, shifting left by three positions is equivalent to multiplying by 2 * 2 * 2 = 8. In general, shifting left by n positions is equivalent to multiplying by 2^n (as long as you don't have bits falling off of the left end).
In the olden days, programmers wrote code like this because left shifts are super duper fast, faster than multiplication and so 8 * y was less optimal than y << 3. But these days, compilers are pretty good at figuring out when to replace something like 8 * y with y << 3.
Therefore, I say it's obfuscated because 8 * y more clearly expresses the intent: the intent of (y << 3) + x is to skip by y blocks of 8, and take the xth position in that block. And this is much more clearly expressed by saying 8 * y + x. Remember, we code in high-level languages for humans to read and understand the code. Our code should be written for the humans. The compiler can do its job of making good machine instructions for the machine to understand.
It's done this way because it's trying to pretend that pieceCodes is a 2D array, just mapped into a 1D array.
That is, piecesCode looks like this
x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
but we can pretend it looks like this
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
See, given (x, y) -> 8y + x we accessing the xth column, yth row of piecesCode. That is, y tells us how many blocks of 8 to skip, and x tells us where to go within that block.
(y << 3) means bit shifting 3 times to the left. It's the same as multiplying by 2^3 = 8. So, whole expression (y << 3) + x becomes y * 8 + x.
It should be written in the form y * 8 + x, because it's more readable and very probably there is no performance gain. Premature optimization is the root of all evil. It's better to left such micro optimizations to the compiler (or JVM).
Moreover, board size could be stored in a constant, to have it only in one place:
final int SIZE = 8;
// ...
for (int y = 0; y < SIZE; y++) {
for (int x = 0; x < SIZE; x++) {
final String pieceCode = pieceCodes[y * SIZE + x];
y * 8 + x is just iterating over a (logically) 2D table with 8 rows and columns, stored as 1D, with 64 cells.
As a final remark, I would like to point out, that in the given code pieceCodes is an array of Strings...
But in fact, it's an array of piece codes. Not just some Strings. Now, "--" works as some magic state and nobody except the programmer knows, what it means. if (pieceCode.length() != 2) also looks bad. So, there should be an object PieceCode and array will be declared as PieceCode[] pieceCodes. In PieceCode we can implement proper equals() method. If PieceCode is only a state, it can be an Enum. For example EMPTY, WHITE_PAWN, WHITE_QUEEN, BLACK_PAWN, BLACK_QUEEN. Comparing Strings is not as fast as comparing Enums. We also have to watch out to write equals(), instead of ==.
From the spec:
The value of n << s is n left-shifted s bit positions; this is equivalent (even if overflow occurs) to multiplication by two to the power s.
<< and >> are bit shift operators. In this case, it converts y to binary and "shifts" over 3 places, adding new bits to the end as required
For example, if y was 8, it would have the value of 1000
y<<3 would shift to the left 3 bits, resulting in 1000000, or 64
That is called a bitwise and bit shift operator. Also, check out the wiki.
Summary of the documentation
The Java programming language also provides operators that perform bitwise and bit shift operations on integral types. The operators discussed in this section are less commonly used.
The unary bitwise complement operator "~" inverts a bit pattern. The signed left shift operator "<<" shifts a bit pattern to the left, and the signed right shift operator ">>" shifts a bit pattern to the right.
The bitwise & operator performs a bitwise AND operation.
The bitwise ^ operator performs a bitwise exclusive OR operation.
The bitwise | operator performs a bitwise inclusive OR operation.
Example code:
class BitDemo {
public static void main(String[] args) {
int bitmask = 0x000F;
int val = 0x2222;
// prints "2"
System.out.println(val & bitmask);
}
}
So... What is a bitwise and bit shift operator?
In order to save time and space, I'll simply include this article explaining all operators in depth!
The code uses an optimization technique that represents a two dimensional array[m][n] as a one dimensional array[m*n]. Both m and n appear to be 8 here (8-queens, chess, maybe?).
The trick is to transpose index tuples (i,j) to indexes for the one dimensional array.
Most of the time, you do this by multiplying i with n and add j.
Since n=8, multiplication can be expressed in this case by shifting 3 bits left. This conveys the message "We are doing adress arithmetic here on some nicely sized (i.e. in terms of power of 2) arrays.", at least to the non-novices.
Quick answer, it's an efficient way of multiplying a number by 8 (2^3=8)
y << 3 means "shifted 3 bits left" ... which is, essentially, another way to do "* 8"
If you do a right-shift (y >> 3), that would be integer divide by eight, but is also useful because the bits fall off the end, and you sort of "drain" the bits if you loop.
It used to be (way way back when) that CPU shift was faster than multiplication, so using "x << 1" was faster than "x * 2". However, that's not true anymore.
I used to see expressions in code like "x << 4 + x << 2 + x << 1" ... which is really "x * 16 + x * 4 + x * 2" or "x * 22".
http://en.wikipedia.org/wiki/Bitwise_operation ... In Java, all integer types are signed, and the "<<" and ">>" operators perform arithmetic shifts. Java adds the operator ">>>" to perform logical right shifts, but because the logical and arithmetic left-shift operations are identical, there is no "<<<" operator in Java.