Algorithm Search⌘K

Proofs: SWAR population count

These are the human proofs of SWAR population count, at full length.

The SWAR population count sums the bits field by field without carries between fields full

This proof shows: correctness.

Fix w∈{8,16,32,64,128}w \in \{8, 16, 32, 64, 128\}. A word is an integer 0≤x<2w0 \le x < 2^w with bits xtx_t. For a field width ff that divides ww, the field ii of a word yy is Fif(y)=⌊y/2fi⌋ mod 2fF_i^f(y) = \lfloor y / 2^{fi} \rfloor \bmod 2^f, for 0≤i<w/f0 \le i < w/f, so y=∑iFif(y) 2fiy = \sum_i F_i^f(y)\, 2^{fi}. Let x0x_0 be the input, and let νif=∑t=fifi+f−1(x0)t\nu_i^f = \sum_{t = fi}^{fi + f - 1} (x_0)_t be the number of 1-bits of x0x_0 in field ii of width ff. Note νi2f=ν2if+ν2i+1f\nu_i^{2f} = \nu_{2i}^f + \nu_{2i+1}^f.

Tool (addition by fields). Let ff divide ww, and let a=∑iai2fia = \sum_i a_i 2^{fi} and b=∑ibi2fib = \sum_i b_i 2^{fi} with 0≤ai,bi0 \le a_i, b_i and ai+bi<2fa_i + b_i < 2^f for each ii. Then a+b=∑i(ai+bi)2fi<2wa + b = \sum_i (a_i + b_i) 2^{fi} < 2^w, and Fif(a+b)=ai+biF_i^f(a + b) = a_i + b_i. Proof. The sum is the stated series by the distributive law. Each coefficient ai+bia_i + b_i lies in [0,2f)[0, 2^f), so the series is the base-2f2^f expansion of a+ba + b, its fields are the coefficients, and the value is at most ∑i(2f−1)2fi=2w−1\sum_i (2^f - 1) 2^{fi} = 2^w - 1. So no reduction modulo 2w2^w happens. □\square

The same argument with ai≥bi≥0a_i \ge b_i \ge 0 gives Fif(a−b)=ai−biF_i^f(a - b) = a_i - b_i and 0≤a−b<2w0 \le a - b < 2^w.

Step L1. Let x=x0x = x_0, f=2f = 2. The word (x≫1)∧M1(x \gg 1) \wedge M_1 has field ii equal to (x0)2i+1(x_0)_{2i+1}: the shift moves bit 2i+12i + 1 to position 2i2i, and M1M_1 keeps exactly the even positions. Field ii of xx is 2(x0)2i+1+(x0)2i≥(x0)2i+12(x_0)_{2i+1} + (x_0)_{2i} \ge (x_0)_{2i+1}. By the subtraction form of the tool, field ii of the result is (x0)2i+1+(x0)2i=νi2(x_0)_{2i+1} + (x_0)_{2i} = \nu_i^2.

Step L2. Let xx have Fi2(x)=νi2≤2F_i^2(x) = \nu_i^2 \le 2. The word x∧M2x \wedge M_2 has 4-bit field jj equal to F2j2(x)=ν2j2F_{2j}^2(x) = \nu_{2j}^2, since M2M_2 keeps the low 2 bits of each 4-bit field. The word (x≫2)∧M2(x \gg 2) \wedge M_2 has 4-bit field jj equal to F2j+12(x)=ν2j+12F_{2j+1}^2(x) = \nu_{2j+1}^2. Their sum per field is νj4≤4<16\nu_j^4 \le 4 < 16. By the tool, Fj4F_j^4 of the result is νj4\nu_j^4.

Step L3. Let xx have Fj4(x)=νj4≤4F_j^4(x) = \nu_j^4 \le 4. The word x+(x≫4)x + (x \gg 4) is a sum by 4-bit fields: field jj gets νj4+νj+14≤8<16\nu_j^4 + \nu_{j+1}^4 \le 8 < 16 (with νw/44=0\nu_{w/4}^4 = 0 at the top). By the tool, field jj of the sum is νj4+νj+14\nu_j^4 + \nu_{j+1}^4. The mask M4M_4 keeps the even 4-bit fields j=2kj = 2k and clears the odd ones. So byte kk of the result is ν2k4+ν2k+14=νk8\nu_{2k}^4 + \nu_{2k+1}^4 = \nu_k^8.

Step L4. Let x=∑kck28kx = \sum_k c_k 2^{8k} with ck=νk8≤8c_k = \nu_k^8 \le 8 and m=w/8m = w/8 bytes. With H=∑l=0m−128lH = \sum_{l=0}^{m-1} 2^{8l},

x⋅H=∑j=02m−2(∑k+l=jck)28j.x \cdot H = \sum_{j=0}^{2m-2} \Big( \sum_{k + l = j} c_k \Big) 2^{8j}.

For j≤m−1j \le m - 1, the coefficient is sj=∑k=0jck≤ν(x0)≤w≤128<256s_j = \sum_{k=0}^{j} c_k \le \nu(x_0) \le w \le 128 < 256. Reduce modulo 2w=28m2^w = 2^{8m}: the terms with j≥mj \ge m are multiples of 2w2^w and vanish, so x⋅H mod 2w=∑j=0m−1sj28jx \cdot H \bmod 2^w = \sum_{j=0}^{m-1} s_j 2^{8j}. Each sj<256s_j < 256, so this is the base-256 expansion, and its top byte is sm−1=∑kck=ν(x0)s_{m-1} = \sum_k c_k = \nu(x_0). The shift right by w−8=8(m−1)w - 8 = 8(m - 1) returns that byte. For w=8w = 8, m=1m = 1, H=1H = 1 and the shift is 0, so the result is c0=ν(x0)c_0 = \nu(x_0) directly.

Theorem. For each word x0x_0, SWAR-POPCOUNT(x0)(x_0) returns ν(x0)\nu(x_0).

Proof. Chain the four steps: after line L1 the 2-bit fields hold νi2\nu_i^2, after line L2 the 4-bit fields hold νj4\nu_j^4, after line L3 the bytes hold νk8\nu_k^8, and line L4 returns ∑kνk8=ν(x0)\sum_k \nu_k^8 = \nu(x_0). Each step used only the hypothesis given by the step before it. The procedure has no loop, so it stops after a fixed number of operations. ■\blacksquare

Where the width bound is used. Step L4 needs sj<256s_j < 256, which holds because sj≤w≤128s_j \le w \le 128. For w≥256w \ge 256 a byte cannot hold the count ww, and the fields must first be doubled to 16 bits.

Back to SWAR population count