1 Bitwise ops
trivial.
2 Swapping
Let \(\otimes\) denote coordinate-wise XOR in \(\mathbb{F}_2^n\). Notice that \((\mathbb{F}_2^n, \otimes)\) forms an Abelian group, where for any vector \(p\), \(p\otimes p = 0\), that is every element is its own inverse. Additionally, \(0\) is the identity element. Therefore, to swap two bits, first note that for any \(a,b \in \mathbb{F}_2^n\) \[\begin{align*} a &= a \otimes 0 = a \otimes b \otimes b \\ b &= 0 \otimes b = a \otimes a \otimes b \end{align*}\] so in code
void swap(int *a, int *b) {
*a ^= *b; // *a = a ^ b
*b ^= *a; // *b = a ^ b ^ b = a ^ 0 = a
*a ^= *b; // *a = a ^ b ^ a = b ^ 0 = b
}
an alternative is using \(+\) since machines do addition modulo \(\mathbb{Z}/2^w\mathbb{Z}\).
3 Bit masks
b = a % 16;
Note that \(16 = 2^4\), so we mask it with the bit sequence \(1111 = 15 = (F)_{16}\), obtaining
b = (a / 8) * 8;
This effectively zeroes the lowest \(3\) bits. I could either
- And-mask the lowest 3 bits then bitwise xor;
- Shift right, then shift left.
Which is better?
4 Bit twiddling
$s0 = 0x8000001F
$s0 = 0x0AAAAAAA
- For every \(1\) in the sequence
$s0
\(\in \mathbb{F}_2^{32}\), it toggles the MSB of$s0
.
5 Loop through array
Tracing. In iterations…
- First iteration. \[\begin{align*} t_1 &\leftarrow M[112] = 108 \\ s_1 &\leftarrow 0 + 108 = 108 \\ t_0 &\leftarrow M[4 + 112] = M[116] = 124 \end{align*}\]
- Second iteration. \[\begin{align*} t_1 &\leftarrow M[124] = 104 \\ s_1 &\leftarrow 108 + 104 = 212 \\ t_0 &\leftarrow M[4 + 124] = M[128] = 100 \end{align*}\]
- Third iteration. \[\begin{align*} t_1 &\leftarrow M[100] = 120 \\ s_1 &\leftarrow 212 + 120 = 332 \\ t_0 &\leftarrow M[4 + 100] = M[104] = 132 \end{align*}\]
Set \(M[104] \leftarrow 0\) will cause it to terminate.
“High-level” code
or in pointer notation,