What is Gosper's Hack?
Gosper’s Hack is a brilliantly optimized bitwise formula that generates the next integer having exactly the same number of set bits (1s) as the current integer. It executes in pure time without any loops, making it the absolute fastest way to iterate through all -combinations of an -element set.
Explanation
- In combinatorics (e.g., in the Traveling Salesperson Problem using Dynamic Programming), you often need to iterate over all subsets of size from a total of elements.
- A subset is typically represented as a bitmask. For example, if and , a bitmask like
00111(decimal 7) represents selecting the first three items. The “next” subset of size 3 is01011(decimal 11). - Traditionally, calculating the “next” mask requires a loop. Gosper’s Hack calculates it directly via arithmetic and bitwise shifts.
How It Works
- Let be the current integer.
-
- Isolate the rightmost set bit:
c = X & -X
- Isolate the rightmost set bit:
-
- Find the block of consecutive set bits starting from the rightmost bit, and flip the bit immediately to its left:
r = X + c
- Find the block of consecutive set bits starting from the rightmost bit, and flip the bit immediately to its left:
-
- Right-shift the block of ones to the far right to reset the sequence, then OR it with the flipped block:
(((r ^ X) >> 2) / c) | r
- Right-shift the block of ones to the far right to reset the sequence, then OR it with the flipped block:
- The combination of these operations produces the lexicographically next bitmask.
Implementation
#include <iostream>
#include <bitset>
// Generates the next integer with the same number of set bits
int nextCombination(int x) {
int c = x & -x;
int r = x + c;
// Shift bits, dividing by c (which is a power of 2, so this is safe)
return (((r ^ x) >> 2) / c) | r;
}
int main() {
// We want all subsets of size 3 (00111 in binary = 7)
int current = 7;
// 0111000 in binary = 56, the maximum value for 3 bits in 6 total slots
int limit = 56;
while (current <= limit) {
std::cout << std::bitset<6>(current) << "\n";
current = nextCombination(current);
}
return 0;
}def next_combination(x):
c = x & -x
r = x + c
# In Python, integer division is //
return (((r ^ x) >> 2) // c) | r
current = 7
for _ in range(5):
print(f"{current:06b}")
current = next_combination(current)
Key Takeaways
- Gosper’s hack eliminates the need for recursive generation or iterative combinations counting.
- It uses fundamental Two’s Complement properties (
x & -x) to manipulate bit groupings. - It is heavily utilized in subset-sum optimizations, dynamic programming over subsets (Bitmask DP), and competitive programming.