Skip to main content
danangell.com/blog about

XOR Swap Explained Visually

A common riddle-like question for programmers asks them to swap the values of two integers without a temporary intermediate value. There are two common solutions that I’m aware of, addition swap and XOR swap. Here’s what each looks like in C:

void addSwap (unsigned int *a, unsigned int *b) {  
    if (a != b) {  
        *a = *a + *b;  
        *b = *a - *b;  
        *a = *a - *b;  
    }  
}
void xorSwap (int *a, int *b) {  
    if (a != b) {  
        *a ^= *b;  
        *b ^= *a;  
        *a ^= *b;  
    }  
}

Credit: https://en.wikipedia.org/wiki/XOR_swap_algorithm

The more interesting of the two is XOR swap. It only uses a single operation, rather than addition and subtraction in addition swap. Wikipedia tries to explain this with bit vectors but I think 1 bit black and white images work better. In the images below, black corresponds to 0 and white corresponds to 1.


A ^ B = A':

Here A becomes white anywhere A or B had a unique presence (only A or only B was black in that pixel). Everywhere else is black.

A B A'

A' ^ B = B':

Now that A is a combination of what was unique in each of the original images, we can apply the same XOR operation to remove what was unique about B, leaving only what was unique about A. So at this point B has swapped and become the circle.

A' B B'

A' ^ B' = A'':

We can perform the same operation as in the previous step to get back the original value of B. Since B holds the circle and we want the square, we remove what was unique about the circle, leaving just the square.

A' B' A''

Here’s the code used to generate the images above:

import sys  
from PIL import Image  

a = Image.open("A.png")  
b = Image.open("B.png")  

if not a.size == b.size:  
    print("Images must have the same dimensions")  
    sys.exit(1)  

if not a.mode == b.mode:  
    print("Images must be the same mode")  
    sys.exit(1)  

result = bytes([  
    a.getpixel((x, y))[0] ^ b.getpixel((x, y))[0]  
    for y in range(a.size[1])  
    for x in range(a.size[0])  
])  

Image.frombytes("P", a.size, result).save("OUT.png")