XOR Properties
Introduction
The XOR (exclusive OR) operation is one of the most versatile bitwise operations in programming. Represented by the ^
symbol in most programming languages, XOR returns 1
if the corresponding bits of its operands are different and 0
if they're the same.
XOR has several intriguing mathematical properties that make it incredibly useful for solving various programming problems efficiently. Understanding these properties can help you develop elegant solutions to complex problems and optimize your code.
Basic XOR Operation
Before diving into the properties, let's understand how XOR works at the bit level:
A | B | A XOR B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
In code, XOR is typically represented with the ^
operator:
int a = 5; // binary: 101
int b = 3; // binary: 011
int result = a ^ b; // binary: 110 = decimal: 6
System.out.println(result); // Output: 6
Key XOR Properties
1. Self-Inverse Property (XOR with same value)
When a value is XORed with itself, the result is always 0.
A ^ A = 0
a = 42
result = a ^ a
print(result) # Output: 0
This works for any value of a
because each bit is XORed with itself, producing 0.
2. XOR with Zero
XORing any value with 0 returns the value unchanged.
A ^ 0 = A
a = 42
result = a ^ 0
print(result) # Output: 42
3. Commutativity
The order of operands doesn't matter in XOR operations.
A ^ B = B ^ A
int a = 25;
int b = 17;
cout << (a ^ b) << endl; // Output: 8
cout << (b ^ a) << endl; // Output: 8 (same result)
4. Associativity
When chaining multiple XOR operations, the grouping doesn't affect the result.
(A ^ B) ^ C = A ^ (B ^ C)
const a = 10;
const b = 20;
const c = 30;
console.log((a ^ b) ^ c); // Output: 16
console.log(a ^ (b ^ c)); // Output: 16
5. Cancellation Property
XORing a sequence with the same value twice cancels out the effect.
A ^ B ^ B = A
This is derived from properties 1 and 3. Since B ^ B = 0
and A ^ 0 = A
, we get A ^ B ^ B = A ^ 0 = A
.
a = 42
b = 17
result = a ^ b ^ b
print(result) # Output: 42 (back to the original value of a)
Practical Applications
1. Swapping Variables Without a Temporary Variable
int a = 5;
int b = 7;
// Swap without a temp variable
a = a ^ b;
b = a ^ b; // Now b = a
a = a ^ b; // Now a = b
std::cout << "a: " << a << ", b: " << b << std::endl; // Output: a: 7, b: 5
How this works:
- After
a = a ^ b
,a
containsa ^ b
. - When
b = a ^ b
, we getb = (a ^ b) ^ b = a ^ (b ^ b) = a ^ 0 = a
. - Finally,
a = a ^ b
gives usa = (a ^ b) ^ a = (a ^ a) ^ b = 0 ^ b = b
.
2. Finding a Non-Duplicated Element
Given an array where every element appears exactly twice except one element, find the unique element.
public static int findUnique(int[] nums) {
int result = 0;
for (int num : nums) {
result ^= num;
}
return result;
}
// Test
int[] arr = {4, 2, 7, 4, 8, 2, 7};
System.out.println(findUnique(arr)); // Output: 8
This works because the duplicated elements cancel each other out (A ^ A = 0
), and only the unique element remains (0 ^ A = A
).
3. Memory-Efficient Toggle
XOR can be used to toggle bits efficiently:
// Toggle the 3rd bit (0-indexed)
int num = 42; // binary: 101010
int mask = 1 << 3; // binary: 001000
num = num ^ mask; // binary: 100010 = decimal: 34
printf("%d\n", num); // Output: 34
// Toggle it back
num = num ^ mask; // binary: 101010 = decimal: 42
printf("%d\n", num); // Output: 42
4. Simple Encryption/Decryption
XOR can be used for basic encryption and decryption:
def xor_encrypt(message, key):
encrypted = ""
for char in message:
encrypted += chr(ord(char) ^ key)
return encrypted
def xor_decrypt(encrypted, key):
return xor_encrypt(encrypted, key) # Same operation for both!
# Example
message = "Hello World"
key = 42
encrypted = xor_encrypt(message, key)
print("Encrypted:", encrypted)
decrypted = xor_decrypt(encrypted, key)
print("Decrypted:", decrypted) # Output: Hello World
This works because of the cancellation property: (A ^ key) ^ key = A
.
5. Computing Parity
You can check if a number has an odd or even number of set bits (1s) using XOR:
function hasOddParity(num) {
let parity = 0;
while (num > 0) {
parity ^= (num & 1); // XOR with least significant bit
num >>= 1; // Right shift by 1
}
return parity === 1; // True if odd number of 1s, false otherwise
}
console.log(hasOddParity(7)); // 7 is 111 in binary, has 3 set bits, Output: true
console.log(hasOddParity(15)); // 15 is 1111 in binary, has 4 set bits, Output: false
Performance Considerations
XOR operations are very efficient because they're directly supported by CPU hardware. Most processors can execute XOR operations in a single clock cycle for register-sized operands. This makes XOR-based algorithms particularly fast.
When dealing with large datasets or performance-critical code, leveraging XOR properties can lead to significant optimizations.
Common Mistakes and Pitfalls
-
Assuming XOR is logical exclusive OR: In some contexts, XOR refers to the logical operation, but in bit manipulation, it operates on each bit independently.
-
Forgetting operator precedence: XOR (
^
) has lower precedence than equality operators, so remember to use parentheses when needed. -
Overcomplicating solutions: Sometimes developers miss opportunities to use XOR for elegant solutions and end up with more complex code.
Summary
XOR is a powerful bitwise operation with several useful properties:
- Self-inverse:
A ^ A = 0
- Identity with zero:
A ^ 0 = A
- Commutativity:
A ^ B = B ^ A
- Associativity:
(A ^ B) ^ C = A ^ (B ^ C)
- Cancellation:
A ^ B ^ B = A
These properties make XOR invaluable for various applications, from efficient variable swapping and finding unique elements to basic encryption and bit toggling.
Practice Exercises
- Write a function to determine if two integers have the same sign without using conditional statements.
- Given an array where all elements appear three times except for one element, find the element that appears only once.
- Implement a function that returns the XOR of all integers from 1 to n efficiently.
- Use XOR to create a function that checks if exactly one of two boolean variables is true.
- Implement a function that finds the missing number in an array containing n-1 distinct numbers from the range [0, n].
Further Reading
- Bit manipulation techniques beyond XOR
- Applications of XOR in cryptography
- XOR-based data structures like XOR linked lists
- XOR in network protocols and error detection
By mastering XOR properties, you'll add a powerful tool to your programming toolkit that can help you solve many problems more efficiently and elegantly.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)