This question already has answers here:
Why is "a^=b^=a^=b;" different from "a^=b; b^=a; a^=b;"?
(6 answers)
Closed 6 years ago.
I tried "swap variable in java without temp" in Java and I found something that bothers me:
int a = 1, b = 2;
b^= a ^= b ^= a;
System.out.println(a + " vs " + b);
The output shows
2 vs 0
However if I separate the leftmost assignment as a individual statement:
int a = 1, b = 2;
a ^= b ^= a;
System.out.println(a + " vs " + b);
b^=a;
System.out.println(a + " vs " + b);
The output is
2 vs 3
2 vs 1
Now the output is as expected.
In C++, the evaluation is ensured from right to left. What the difference, in terms of language spec, tells Java could lead such expected result?
According to the JLS, x ^= y is equivalent to x = (x) ^ (y) (there's also a cast in there, but if you're dealing with ints, the cast doesn't matter anyway). So this:
b ^= a ^= b ^= a;
is equivalent to
b = (b) ^ (a = (a) ^ (b = (b) ^ (a)));
// ^^^
In Java, arguments to an operator are always evaluated left to right. So the b that I pointed to in the above is the original value of b, since it's evaluated before the assignment to b in the right part of the expression. That means the expression is not equivalent to
b ^= a;
a ^= b;
b ^= a;
since the third statement uses the new value of b as the left operand to ^.
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;
This question already has an answer here:
Order of operations for compound assignment operators in Java
(1 answer)
Closed 6 years ago.
int a = 2;
int b = 3;
int c = 10;
a +=(a += b) + c; // this will be same as --> a = a+((a= a+b) +c);
/* 2+((2=2+3)+10)
after adding 2+3
now value a = 5;
5 +((5)+10)
5 + (15)
a = 20
*/
System.out.println("a: "+a); // a:17
when i execute above program the answer is a:17 why not a:20 ?
according to me.
After resolving (a += b) now the value of a should be 5 then (a += b) + c would be 15 and after that a +=(a += b) + c; should be 20
please help me understand thanks.
The compound assignment operator stores the original value of the left operand before evaluating the second operand and performing the compound assignment (addition + assignment in this example).
Therefore
a += (a += b) + c;
is equivalent to :
int temp = a;
a = temp + (a += b) + c;
2 + 2 + 3 + 10 = 17
This is a good example of where order of evaluation and precedence don't match. They usually do which makes it confusing when there is a difference, as you mention the expression is evaluated left to right like this
int s = a; // stack
int t = a + b; // second stack value.
s += t;
s += c;
a = t;
a = s;
Note the (a+=b) is the same as (a+b) in this case.
In Java, you can replace a += b with a = a + b. And that is very important.
Hence your expression is equivalent to
a = a + (a = a + b) + c
Note that this will be evaluated as a = Term1 + Term2 + Term3 and in the order left to right.
Term1 is 2.
Term2 is the only tricky one. It is 5 (and has the side-effect of increasing a to 5 but that gets clobbered by the eventual assignment).
Term3 is 10.
That recovers the total, 17.
Note that the behaviour of this expression in C and C++ is undefined.
It is a bit tricky to understand. Although you have a += b on the right-hand side, that doesn't change the value of a that's used for the += at the beginning of the expression; that will still be 2. E.g.:
a += (a += b) + c;
a = 2 + (a[still 2] += 3) + 10
a = 2 + (5) + 10
a = 17
The a += b on the right-hand side is really just a a + b, since this is all on the right-hand side of a += already directed at a.
Details in JLS§15.26.2: Compound Assignment Operators.
First you do a+=b so 2+3 you have 5. Then a+= your answer (here 5) so 2+=5 = 7. Then 7+10 = 17
Here is the reference implementation I got, the confusion is, I think there is no need for recursion. I post both reference code and my thought below here, for the difference see line 5.
Any insights are appreciated. Please feel free to correct me if I am wrong.
Reference implementation:
1 int add_no_arithm(int a, int b) {
2 if (b == 0) return a;
3 int sum = a ^ b; // add without carrying
4 int carry = (a & b) << 1; // carry, but don’t add
5 return add_no_arithm(sum, carry); // recurse
6 }
Another implementation in my thought,
1 int add_no_arithm(int a, int b) {
2 if (b == 0) return a;
3 int sum = a ^ b; // add without carrying
4 int carry = (a & b) << 1; // carry, but don’t add
5 return sum ^ carry;
6 }
BTW, tried 8+8 in Python - worked for me:
Is the recursion needed?
a = 8
b = 8
sum = a ^ b
carry = (a & b) << 1
print(sum^carry) # 16
The second approach doesn't work with 1 + 3.
Here are the steps
a == 01
b == 11
sum = a^b == 10
carry = (a&b) << 1 == 10
sum ^ carry == 00 // wrong answer! 1 + 3 == 4
Just doing ^ at the last step is not enough, as there may be a carry in that sum.
The question is, whether recursive is needed?
Yes, it is. You can see this for yourself by experimenting with other numbers, instead of just 8 + 8. For example, try 21 and 15, without recursion this gives output of 26.
The bitwise XOR operator ^ is only equivalent to the addition operator + if there is no binary carrying in the sums. If there is binary carrying, then they are not equivalent. For example, 8 + 7 equals 8 ^ 7 equals 15, but 8 + 8 is 16 while 8 ^ 8 is 0.
Even if you have calculated the sum-no-carry and the carry-no-sum correctly, what if those two numbers, when added, would produce a binary carry? Then your ^ operator at the end would be incorrect. Without the + operator, the only option I see is to recurse, to add those numbers. This will recur until one of the numbers is 0.
Example:
add(no_arithm(18, 6))
sum = a^b 18 ^ 6 is 20.
carry = (a & b) << 1 18 & 6 is 2, bit shift left 1 is 4.
return sum ^ carry 20 ^ 4 is 16, incorrect (18 + 6 = 24).
Will this work?
import java.util.*;
public class Solution {
public static int sumOfTwoNumbers(int a, int b) {
if (b<0){
for(int j = 1; j<=-b;j++)
--a;
}
if(b>0){
for (int i = 1; i <= b; i++){
a++;
}
}
return a;
}
This question already has answers here:
Difference between a += 10 and a = a + 10 in java? [duplicate]
(5 answers)
Closed 8 years ago.
I've been told that there are differences between a+=b; and a=a+b; which can result in only one of those being legal depending on the type declerations.
Does anyone have an example of this?
There is basically no difference, however there is a subtle difference.
The arithmetic assignment operators do an implicit cast. e.g.
byte a = 1;
int b = 2;
a += b; // compiles
a = a + b; // doesn't compile as a byte + int = int
a = (byte) (a + b); // compiles as this is the same as +=
For more weird examples.
int a = 5;
a += 1.5f;
// a == 6
char ch = '0'; // (char) 49
ch *= 1.1; // ch = '4';
long l = Integer.MAX_VALUE;
l += 0.0f; // i = (long ) ((long ) l + 0.0f)
// i == Integer.MAX_VALUE + 1L; WTF!?
// l is no longer Integer.MAX_VALUE due to rounding error.
The JLS (section 15.26.2) says:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
The presence of the type-cast means that there are a couple of edge cases where a = a op b means something different to a op= b.
See Peter Lawrey's answer for one example. It is when a is a byte and b is an int and the "op" is +. The "gotcha" is a + b produces an int, which then can't be assigned to a ... without a typecast.
The same scenario applies with other types for a and b and for other arithmentic and bitwise operators.
int a = 10;
int b = 20;
a=a+b; // 30
a+=b; // 30
System.out.println(a);
Both will give the same answer.
I had come across a question for which I am not able to find out why its output is coming as
7
when I calculate mathematically it can produce output as 7, 8 or any other number So my question is on what basis its coming as 7 only
interface InterfaceA
{
int A = InterfaceB.B * 2;
}
interface InterfaceB
{
int B = InterfaceC.C + 1;
}
interface InterfaceC extends InterfaceA
{
int C = A + 1;
}
public class TestInterface implements InterfaceA, InterfaceB, InterfaceC {
public static void main(String[] args) {
System.out.println(A + B + C);
}
}
Obviously code like this should never actually occur. It's horrendous. I don't think you should spend too much time worrying about why it gives 7, but it's actually not too hard to see why.
The first field value to be evaluated is InterfaceA.A, so the VM starts to initialize InterfaceA. That requires InterfaceB.B, so it starts to initialize InterfaceB. That requires InterfaceC.C, so it starts to initialize InterfaceC.
Now although InterfaceC.C refers to InterfaceA.A, the VM is already initializing InterfaceA, so it just proceeds regardless (as per section 12.4.2 of the JLS):
If the Class object for C indicates that initialization is in progress for C by the current thread, then this must be a recursive request for initialization. Release LC and complete normally.
So InterfaceA.A is still 0 (we're still trying to work out what value it should have, and 0 is the default value for int), and InterfaceC.C gets a value of 1 (0 + 1). Then InterfaceB.B gets a value of 2 (1 + 1), and InterfaceA.A gets a value of 4 (2 * 2).
Sum all of those field values, and you end up with 7.
If you use a different expression, you'll get a different value because you'll see a different interface being initialized last, although it only depends on the first field which you refer to:
A + B + C = 7 (A = 4, B = 2, C = 1)
A + C + B = 7 (A = 4, B = 2, C = 1)
B + A + C = 3 (A = 0, B = 2, C = 1)
B + C + A = 3 (A = 0, B = 2, C = 1)
C + A + B = 6 (A = 2, B = 1, C = 3)
C + B + A = 6 (A = 2, B = 1, C = 3)
(You have to replace the existing line of code of course, as this is about type initialization - if you just add more System.out.println lines you'll get the same answer for all the above expressions.)
System.out.println(A + B + C);
When you asked for A ( InterfaceB.B * 2;) , you need B
So, B needs to be resolve,
int B = InterfaceC.C + 1;
When you asked for B ( InterfaceC.C + 1) , you need C
So, C needs to be resolve,
int C = A + 1; // 0+1 =1
A is not yet resolved and default is 0
So int C is 1.
Now , You need B.
int B = InterfaceC.C + 1; // 1+1 =2
Now
int A = InterfaceB.B * 2; // 2*2 =4
Finally
1+2+4 =7
When you run the code,then execution starts from the main method.In main its System.out.println(A+B+C) and as you know control goes from right to left.
Here in this case C is executed first(Because it is present at extreme right) meaning c=A+1 but A is 0 so C=1.
Now B is present to left of C so B will be executed this means B=C+1 so B=2(because c is already 1)
As A is at extreme left so Now A is executed this means A=B*2
So finally its 4+2+1=7
Similarly if you print System.out.println(B+C+A); then you will get 3