Algorithm Search⌘K

Proofs: Gosper's hack

These are the human proofs of Gosper's hack, at full length.

Gosper's hack returns the next larger word with the same number of ones full

This proof shows: correctness.

All arithmetic is on unsigned ww-bit words, modulo 2w2^w. For an integer v≥0v \ge 0 we write pop⁡(v)\operatorname{pop}(v) for the number of ones in its binary form.

Setup. Let 0<x<2w0 < x < 2^w. Let tt be the number of trailing zeros of xx, and let m≥1m \ge 1 be the length of the block of ones that starts at bit tt, so that bits t,…,t+m−1t, \ldots, t + m - 1 of xx are ones and bit t+mt + m is a zero or lies outside the word. Then there is a unique integer a≥0a \ge 0 with

x=a⋅2t+m+1+(2m−1)⋅2t.x = a \cdot 2^{t+m+1} + (2^m - 1) \cdot 2^t .

We assume t+m<wt + m < w, that is, the block does not end at the top bit of the word.

Claim. Under this assumption, GOSPER-NEXT(x)(x) returns z=a⋅2t+m+1+2t+m+2m−1−1z = a \cdot 2^{t+m+1} + 2^{t+m} + 2^{m-1} - 1, and zz is the least integer y>xy > x with pop⁡(y)=pop⁡(x)\operatorname{pop}(y) = \operatorname{pop}(x). Also z<2wz < 2^w.

Step 1: the value of each line.

  • Line L1. In two's complement, −x=2w−x-x = 2^w - x. The low tt bits of xx are 0 and bit tt is 1, so the low tt bits of 2w−x2^w - x are 0, bit tt is 1, and each bit above tt is the complement of the bit of xx. The AND keeps only bit tt. So smallest=2tsmallest = 2^t.
  • Line L2. x+2t=a⋅2t+m+1+(2m−1)⋅2t+2t=a⋅2t+m+1+2t+mx + 2^t = a \cdot 2^{t+m+1} + (2^m - 1) \cdot 2^t + 2^t = a \cdot 2^{t+m+1} + 2^{t+m}. Since t+m<wt + m < w and x<2wx < 2^w, bit t+mt + m of xx is a zero inside the word, so a⋅2t+m+1+2t+m<2wa \cdot 2^{t+m+1} + 2^{t+m} < 2^w and no wrap-around happens. So ripple=a⋅2t+m+1+2t+mripple = a \cdot 2^{t+m+1} + 2^{t+m}.
  • Line L3. xx and rippleripple agree on the bits t+m+1t + m + 1 and above (both hold aa) and on the bits below tt (both 0). On bits tt to t+m−1t + m - 1, xx has ones and rippleripple zeros; on bit t+mt + m, xx has a zero and rippleripple a one. So ones=(2m+1−1)⋅2tones = (2^{m+1} - 1) \cdot 2^t.
  • Line L4. A logical shift right by 2 is ⌊⋅/4⌋\lfloor \cdot / 4 \rfloor, and unsigned division by 2t2^t is ⌊⋅/2t⌋\lfloor \cdot / 2^t \rfloor. For integers N≥0N \ge 0 and b,c≥1b, c \ge 1, ⌊⌊N/b⌋/c⌋=⌊N/(bc)⌋\lfloor \lfloor N / b \rfloor / c \rfloor = \lfloor N / (bc) \rfloor. So the new value is ⌊(2m+1−1)⋅2t/2t+2⌋=⌊(2m+1−1)/4⌋\lfloor (2^{m+1} - 1) \cdot 2^t / 2^{t+2} \rfloor = \lfloor (2^{m+1} - 1)/4 \rfloor. Since (2m+1−1)/4=2m−1−1/4(2^{m+1} - 1)/4 = 2^{m-1} - 1/4 and 2m−1−12^{m-1} - 1 is an integer when m≥1m \ge 1, this is 2m−1−12^{m-1} - 1.
  • Line L5. 2m−1−1<2m−1≤2t+m2^{m-1} - 1 < 2^{m-1} \le 2^{t+m}, so the ones of 2m−1−12^{m-1} - 1 lie below the lowest one of rippleripple, and the OR is a sum: the result is z=a⋅2t+m+1+2t+m+2m−1−1z = a \cdot 2^{t+m+1} + 2^{t+m} + 2^{m-1} - 1, and z<2t+m+1(a+1)≤2wz < 2^{t+m+1}(a + 1) \le 2^w.

Step 2: zz has the right count and is larger. The three parts of zz use disjoint bits, so pop⁡(z)=pop⁡(a)+1+(m−1)=pop⁡(a)+m=pop⁡(x)\operatorname{pop}(z) = \operatorname{pop}(a) + 1 + (m - 1) = \operatorname{pop}(a) + m = \operatorname{pop}(x). The integers zz and xx agree on the bits above t+mt + m, and at bit t+mt + m the integer zz has a 1 and xx a 0. So z>xz > x.

Step 3: zz is the least. Let y>xy > x with pop⁡(y)=pop⁡(x)\operatorname{pop}(y) = \operatorname{pop}(x). Let pp be the highest bit where yy and xx differ. Since y>xy > x, bit pp of yy is 1 and bit pp of xx is 0.

  • Case p<tp < t. Then all ones of xx lie above pp (the lowest one is at tt), and yy has the same bits as xx above pp and one more 1 at bit pp. So pop⁡(y)≥pop⁡(x)+1\operatorname{pop}(y) \ge \operatorname{pop}(x) + 1, a contradiction.
  • Case t≤p≤t+m−1t \le p \le t + m - 1. Bit pp of xx is 1, a contradiction.
  • Case p>t+mp > t + m. Then zz and yy agree with xx above pp, bit pp of zz is bit pp of xx, which is 0, and bit pp of yy is 1. So z<yz < y.
  • Case p=t+mp = t + m. Then yy and zz agree on all bits from t+mt + m up. Let ℓ=y mod 2t+m\ell = y \bmod 2^{t+m}. The ones of yy at bit t+mt + m and above number pop⁡(a)+1\operatorname{pop}(a) + 1, so pop⁡(ℓ)=pop⁡(x)−pop⁡(a)−1=m−1\operatorname{pop}(\ell) = \operatorname{pop}(x) - \operatorname{pop}(a) - 1 = m - 1. An integer with m−1m - 1 ones is at least 2m−1−12^{m-1} - 1, the integer whose ones are the m−1m - 1 lowest bits. So ℓ≥2m−1−1=z mod 2t+m\ell \ge 2^{m-1} - 1 = z \bmod 2^{t+m}, and y≥zy \ge z.

In each possible case y≥zy \ge z. With Step 2, zz is the least integer above xx with pop⁡(x)\operatorname{pop}(x) ones. ■\blacksquare

The case t+m=wt + m = w. Then x=(2m−1)⋅2w−mx = (2^m - 1) \cdot 2^{w-m} is the largest ww-bit word with mm ones, so no answer exists inside the word. Line L2 wraps to ripple=0ripple = 0, line L3 gives ones=xones = x, and line L4 gives ⌊(2m−1)⋅2w−m/2w−m+2⌋=⌊(2m−1)/4⌋\lfloor (2^m - 1) \cdot 2^{w-m} / 2^{w-m+2} \rfloor = \lfloor (2^m - 1)/4 \rfloor, which is 2m−2−12^{m-2} - 1 for m≥2m \ge 2 and 0 for m=1m = 1. The result is smaller than xx and has max⁡(m−2,0)\max(m - 2, 0) ones, so a caller must stop before this call.

Enumeration. Let 0<k≤n<w0 < k \le n < w, start with x0=2k−1x_0 = 2^k - 1, and set $x_{i+1} = $ GOSPER-NEXT(xi)(x_i) while xi<2nx_i < 2^n. Each xi<2nx_i < 2^n has its top bit at most n−1<w−1n - 1 < w - 1, so the assumption t+m<wt + m < w holds and the claim applies. By the claim, the sequence is strictly increasing and contains every integer in [x0,2n)[x_0, 2^n) with kk ones. The least integer with kk ones is 2k−1=x02^k - 1 = x_0. So the values below 2n2^n are exactly the (nk)\binom{n}{k} masks of the kk-subsets of {0,…,n−1}\{0, \ldots, n - 1\}, in increasing order, and the loop stops after (nk)\binom{n}{k} values, because the strictly increasing sequence of integers with kk ones has only (nk)\binom{n}{k} terms below 2n2^n. ■\blacksquare

Back to Gosper's hack