Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is "a^=b^=a^=b;" different from "a^=b; b^=a; a^=b;"?

Tags:

I tried some code to swap two integers in Java without using a 3rd variable, using XOR.

Here are the two swap functions I tried:

package lang.numeric;

public class SwapVarsDemo {

    public static void main(String[] args) {
        int a = 2984;
        int b = 87593;
        swapDemo1(a,b);
        swapDemo2(a,b);
    }

    private static void swapDemo1(int a, int b) {
        a^=b^=a^=b;
        System.out.println("After swap: "+a+","+b);
    }

    private static void swapDemo2(int a, int b) {
        a^=b;
        b^=a;
        a^=b;
        System.out.println("After swap: "+a+","+b);
    }

}

The output produced by this code was this:

After swap: 0,2984
After swap: 87593,2984

I am curious to know, why is this statement:

        a^=b^=a^=b;

different from this one?

        a^=b;
        b^=a;
        a^=b;
like image 651
Abhishek Oza Avatar asked Feb 26 '14 14:02

Abhishek Oza


2 Answers

The issue is the order of evaluation:

See JLS section 15.26.2

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.

Otherwise, the saved value of the left-hand variable and the value of the right-hand operand are used to perform the binary operation indicated by the compound assignment operator. If this operation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

Otherwise, the result of the binary operation is converted to the type of the left-hand variable, subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.

So your expression does:

a^=b^=a^=b;

  1. evaluate a
  2. evaluate b^=a^=b
  3. xor the two (so the a in step one does not have ^=b applied to it yet)
  4. store the result in a

In other words, your expression is equivalent to the following java code:

    int a1 = a;
    int b2 = b;
    int a3 = a;
    a = a3 ^ b;
    b = b2 ^ a;
    a = a1 ^ b;

You can see that from the disassembled version of your method:

  private static void swapDemo1(int, int);
    Code:
       0: iload_0       
       1: iload_1       
       2: iload_0       
       3: iload_1       
       4: ixor          
       5: dup           
       6: istore_0      
       7: ixor          
       8: dup           
       9: istore_1      
      10: ixor          
      11: istore_0  
like image 130
Erwin Bolwidt Avatar answered Sep 22 '22 12:09

Erwin Bolwidt


Because a ^= b ^= a ^= b; is parsed like:

a ^= (b ^= (a ^= b));

Which can be reduced to:

a ^= (b ^= (a ^ b));

So b will have the value b ^ (a ^ b) and finally a will be a ^ (b ^ (a ^ b).

like image 24
Maroun Avatar answered Sep 22 '22 12:09

Maroun