Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does swapping values with XOR fail when using this compound form?

Tags:

c#

swap

xor

I found this code to swap two numbers without using a third variable, using the XOR ^ operator.

Code:

int i = 25; int j = 36; j ^= i;        i ^= j; j ^= i;  Console.WriteLine("i:" + i + " j:" + j);  //numbers Swapped correctly //Output: i:36 j:25 

Now I changed the above code to this equivalent code.

My Code:

int i = 25; int j = 36;  j ^= i ^= j ^= i;   // I have changed to this equivalent (???).  Console.WriteLine("i:" + i + " j:" + j);  //Not Swapped correctly             //Output: i:36 j:0 

Now, I want to know, Why does my code give incorrect output?

like image 878
Javed Akram Avatar asked Apr 07 '11 06:04

Javed Akram


People also ask

How XOR works in swapping?

The bitwise XOR operator can be used to swap two variables. The XOR of two numbers x and y returns a number that has all the bits as 1 wherever bits of x and y differ. For example, XOR of 10 (In Binary 1010) and 5 (In Binary 0101) is 1111, and XOR of 7 (0111) and 5 (0101) is (0010).

What instruction is used to swap the values two separate storage locations?

In computer programming, the exclusive or swap (sometimes shortened to XOR swap) is an algorithm that uses the exclusive or bitwise operation to swap the values of two variables without using the temporary variable which is normally required.


1 Answers

EDIT: Okay, got it.

The first point to make is that obviously you shouldn't use this code anyway. However, when you expand it, it becomes equivalent to:

j = j ^ (i = i ^ (j = j ^ i)); 

(If we were using a more complicated expression such as foo.bar++ ^= i, it would be important that the ++ was only evaluated once, but here I believe it's simpler.)

Now, the order of evaluation of the operands is always left to right, so to start with we get:

j = 36 ^ (i = i ^ (j = j ^ i)); 

This (above) is the most important step. We've ended up with 36 as the LHS for the XOR operation which is executed last. The LHS is not "the value of j after the RHS has been evaluated".

The evaluation of the RHS of the ^ involves the "one level nested" expression, so it becomes:

j = 36 ^ (i = 25 ^ (j = j ^ i)); 

Then looking at the deepest level of nesting, we can substitute both i and j:

j = 36 ^ (i = 25 ^ (j = 25 ^ 36)); 

... which becomes

j = 36 ^ (i = 25 ^ (j = 61)); 

The assignment to j in the RHS occurs first, but the result is then overwritten at the end anyway, so we can ignore that - there are no further evaluations of j before the final assignment:

j = 36 ^ (i = 25 ^ 61); 

This is now equivalent to:

i = 25 ^ 61; j = 36 ^ (i = 25 ^ 61); 

Or:

i = 36; j = 36 ^ 36; 

Which becomes:

i = 36; j = 0; 

I think that's all correct, and it gets to the right answer... apologies to Eric Lippert if some of the details about evaluation order are slightly off :(

like image 104
Jon Skeet Avatar answered Sep 26 '22 06:09

Jon Skeet