XOR swap algorithm
From Wikipedia, the free encyclopedia
In computer programming, the XOR swap is an algorithm that uses the XOR bitwise operation to swap distinct values of variables having the same data type without using a temporary variable.
Contents |
[edit] The algorithm
Standard swapping algorithms require the use of a temporary storage variable. Using the XOR swap algorithm, however, no temporary storage is needed. The algorithm is as follows:
X := X XOR Y Y := X XOR Y X := X XOR Y
The algorithm typically corresponds to three machine code instructions. For example, in IBM System/370 assembly code:
XR R1,R2 XR R2,R1 XR R1,R2
where R1 and R2 are registers and each XR operation leaves its result in the register named in the first argument.
However, the problem still remains that if x and y use the same storage location, the value stored in that location will be zeroed out by the first XOR instruction, and then remain zero; it will not be "swapped with itself".
[edit] Proof that XOR swap works
By the symmetric property of XOR, we can prove that this operation will always swap two values. We will use the following properties of XOR. ^ shall denote the XOR operation, as in C and other programming languages.
- Commutative: A ^ B = B ^ A
- Associative: A ^ (B ^ C) = (A ^ B) ^ C = A ^ B ^ C
- Identity exists: A ^ 0 = A (that is, 0 is the identity element for XOR)
- Each element is its own inverse: A ^ A = 0
Let X have value A and Y have value B. We walk through each step of the XOR operation:
X := X ^ Y (now X = A ^ B) Y := X ^ Y (now Y = X ^ Y = (A ^ B) ^ (B) = A ^ B ^ B = A ^ (B ^ B) = A ^ 0 = A) X := X ^ Y (now X = X ^ Y = (A ^ B) ^ (A) = A ^ B ^ A = (A ^ A) ^ B = 0 ^ B = B)
[edit] Code examples
Note that we do not swap the integers passed immediately, but first check if their memory locations are distinct. This will remove problems caused by possible aliasing.
[edit] Pascal
A Pascal procedure to swap two integers using the XOR swap algorithm:
procedure XorSwap(var X, Y: integer); begin {note: we are comparing the values of X and Y rather than the addresses because standard Pascal lacks an address-of operator} if X <> Y then begin X := X xor Y; Y := X xor Y; X := X xor Y end end
[edit] C
A C function that implements the XOR swap algorithm:
void xorSwap (int *x, int *y) { if (x != y) { *x ^= *y; *y ^= *x; *x ^= *y; } }
The body of this function is sometimes seen reduced to if (x != y) *x^=*y^=*x^=*y;
. This, however, is not valid C, because of a lack of sequence points.
[edit] Reasons for use in practice
The algorithm is not uncommon in embedded assembly code, where there is often very limited space available for temporary swap space, and this form of swap can also avoid a load/store which can make things much faster. On some architectures, certain operations require their operands to be in particular registers, requiring a swap; and all available "temporary" registers may be in use storing other data. Some optimizing compilers can generate code using XOR swap in these situations.
[edit] Reasons for avoidance in practice
On modern (desktop) CPUs, the XOR technique is considerably slower than using a temporary variable to do swapping. One reason is that modern CPUs strive to execute commands in parallel; see Instruction pipeline. In the XOR technique, the inputs to each operation depend on the results of the previous operation, so they must be executed in strictly sequential order. If efficiency is of tremendous concern, it is advised to test the speeds of both the XOR technique and temporary variable swapping on the target architecture.
[edit] The XCHG instruction
Modern optimizing compilers work by translating the code they are given into an internal flow-based representation which they transform in many ways before producing their machine-code output. These compilers are more likely to recognize and optimize a conventional (temporary-based) swap than to recognize the high-level language statements that correspond to a XOR swap. Many times, what is written as a swap in high-level code is translated by the compiler into a simple internal note that two variables have swapped memory addresses, rather than any amount of machine code. Other times, when the target architecture supports it, the compiler can use a single XCHG (exchange) instruction which performs the swap in a single operation.
An XCHG operation was available as long ago as 1964, on the PDP-6 (where it was called EXCH) and in 1970 on the Datacraft 6024 series (where it was called XCHG). The Intel 8086, released in 1986, also included an instruction named XCHG. All three of these instructions swapped registers with registers, or registers with memory, but were unable to swap the contents of two memory locations. The Motorola 68000's EXG operation can only swap registers with registers. The PDP-10 inherited the PDP-6's EXCH instruction, but the PDP-11 (the machine on which the C programming language was developed) did not.
However, the XCHG instruction in modern processors (e.g. x86) should only be used to swap registers and not memory, as an implicit LOCK instruction may be imposed by the processor on the memory location(s) involved so that the operation is atomic.
[edit] Aliasing
The XOR swap is also complicated in practice by aliasing. As noted above, if an attempt is made to XOR-swap the contents of some location with itself, the result is that the location is zeroed out and its value lost. Therefore, XOR swapping must not be used blindly in a high-level language if aliasing is possible.
If the language permits, the ugly details of swapping should be hidden inside a macro or an inline function. Not only will it make the code clearer, but it will also be possible to switch to a different swapping routine if necessary.
[edit] Variations
The underlying principle of the XOR swap algorithm can be applied to any reversible binary operation. Replacing XOR by addition and subtraction gives a slightly different, but largely equivalent, formulation:
procedure AddSwap(var X, Y: integer); begin if X <> Y then begin X := X + Y; Y := X - Y; X := X - Y end end
Unlike the XOR swap, this variation requires that the underlying processor or programming language uses a method such as modular arithmetic or bignums to guarantee that the computation of X + Y
cannot cause an error due to integer overflow. Therefore, it is seen even more rarely in practice than the XOR swap.