bit-operations.tex (8816B)

1 \chapter{Bit operations} 2 \label{chap:Bit operations} 3 4 libzahl provides a number of functions that operate on 5 bits. These can sometimes be used instead of arithmetic 6 functions for increased performance. You should read 7 the sections in order. 8 9 \vspace{1cm} 10 \minitoc 11 12 13 \newpage 14 \section{Boundary} 15 \label{sec:Boundary} 16 17 To retrieve the index of the lowest set bit, use 18 19 \begin{alltt} 20 size_t zlsb(z_t a); 21 \end{alltt} 22 23 \noindent 24 It will return a zero-based index, that is, if the 25 least significant bit is indeed set, it will return 0. 26 27 If {\tt a} is a power of 2, it will return the power 28 of which 2 is raised, effectively calculating the 29 binary logarithm of {\tt a}. Note, this is only if 30 {\tt a} is a power of two. More generally, it returns 31 the number of trailing binary zeroes, if equivalently 32 the number of times {\tt a} can evenly be divided by 33 2. However, in the special case where $a = 0$, 34 {\tt SIZE\_MAX} is returned. 35 36 A similar function is 37 38 \begin{alltt} 39 size_t zbit(z_t a); 40 \end{alltt} 41 42 \noindent 43 It returns the minimal number of bits require to 44 represent an integer. That is, $\lceil \log_2 a \rceil - 1$, 45 or equivalently, the number of times {\tt a} can be 46 divided by 2 before it gets the value 0. However, in 47 the special case where $a = 0$, 1 is returned. 0 is 48 never returned. If you want the value 0 to be returned 49 if $a = 0$, write 50 51 \begin{alltt} 52 zzero(a) ? 0 : zbits(a) 53 \end{alltt} 54 55 The definition ``it returns the minimal number 56 of bits required to represent an integer,'' 57 holds true if $a = 0$, the other divisions 58 do not hold true if $a = 0$. 59 60 61 \newpage 62 \section{Shift} 63 \label{sec:Shift} 64 65 There are two functions for shifting bits 66 in integers: 67 68 \begin{alltt} 69 void zlsh(z_t r, z_t a, size_t b); 70 void zrsh(z_t r, z_t a, size_t b); 71 \end{alltt} 72 73 \noindent 74 {\tt zlsh} performs a left-shift, and {\tt zrsh} 75 performs a right-shift. That is, {\tt zlsh} adds 76 {\tt b} trailing binary zeroes, and {\tt zrsh} 77 removes the lowest {\tt b} binary digits. So if 78 79 $a = \phantom{00}10000101_2$ then 80 81 $r = 1000010100_2$ after calling {\tt zlsh(r, a, 2)}, and 82 83 $r = \phantom{0100}100001_2$ after calling {\tt zrsh(r, a, 2)}. 84 \vspace{1em} 85 86 {\tt zlsh(r, a, b)} is equivalent to $r \gets a \cdot 2^b$, 87 and {\tt zrsh(r, a, b)} is equivalent to $r \gets a \div 2^b$, 88 with truncated division, {\tt zlsh} and {\tt zrsh} are 89 significantly faster than {\tt zpowu} and should be used 90 whenever possible. {\tt zpowu} does not check if it is 91 possible for it to use {\tt zlsh} instead, even if it 92 would, {\tt zlsh} and {\tt zrsh} would still be preferable 93 in most cases because it removes the need for {\tt zmul} 94 and {\tt zdiv}, respectively. 95 96 {\tt zlsh} and {\tt zrsh} are implemented in two steps: 97 (1) shift whole characters, that is, groups of aligned 98 64 bits, and (2) shift on a bit-level between characters. 99 100 If you are implementing a calculator, you may want to 101 create a wrapper for {\tt zpow} that uses {\tt zlsh} 102 whenever possible. One such wrapper could be 103 104 \begin{alltt} 105 void 106 pow(z_t r, z_t a, z_t b) 107 \{ 108 size_t s1, s2; 109 if ((s1 = zlsb(a)) + 1 == zbits(a) && 110 zbits(b) <= 8 * sizeof(SIZE_MAX)) \{ 111 s2 = zzero(b) ? 0 : b->chars[0]; 112 if (s1 <= SIZE_MAX / s2) \{ 113 zsetu(r, 1); 114 zlsh(r, r, s1 * s2); 115 return; 116 \} 117 \} 118 zpow(r, a, b); 119 \} 120 \end{alltt} 121 122 123 \newpage 124 \section{Truncation} 125 \label{sec:Truncation} 126 127 In \secref{sec:Shift} we have seen how bit-shift 128 operations can be used to multiply or divide by a 129 power of two. There is also a bit-truncation 130 operation: {\tt ztrunc}, which is used to keep 131 only the lowest bits, or equivalently, calculate 132 the remainder of a division by a power of two. 133 134 \begin{alltt} 135 void ztrunc(z_t r, z_t a, size_t b); 136 \end{alltt} 137 138 \noindent 139 is consistent with {\tt zmod}; like {\tt zlsh} and 140 {\tt zrsh}, {\tt a}'s sign is preserved into {\tt r} 141 assuming the result is non-zero. 142 143 {\tt ztrunc(r, a, b)} stores only the lowest {\tt b} 144 bits in {\tt a} into {\tt r}, or equivalently, 145 calculates $r \gets a \mod 2^b$. For example, if 146 147 $a = 100011000_2$ then 148 149 $r = \phantom{10001}1000_2$ after calling 150 {\tt ztrunc(r, a, 4)}. 151 152 153 \newpage 154 \section{Split} 155 \label{sec:Split} 156 157 In \secref{sec:Shift} and \secref{sec:Truncation} 158 we have seen how bit operations can be used to 159 calculate division by a power of two and 160 modulus a power of two efficiently using 161 bit-shift and bit-truncation operations. libzahl 162 also has a bit-split operation that can be used 163 to efficiently calculate both division and 164 modulus a power of two efficiently in the same 165 operation, or equivalently, storing low bits 166 in one integer and high bits in another integer. 167 This function is 168 169 \begin{alltt} 170 void zsplit(z_t high, z_t low, z_t a, size_t b); 171 \end{alltt} 172 173 \noindent 174 Unlike {\tt zdivmod}, it is not more efficient 175 than calling {\tt zrsh} and {\tt ztrunc}, but 176 it is more convenient. {\tt zsplit} requires 177 that {\tt high} and {\tt low} are from each 178 other distinct references. 179 180 Calling {\tt zsplit(high, low, a, b)} is 181 equivalent to 182 183 \begin{alltt} 184 ztrunc(low, a, delim); 185 zrsh(high, a, delim); 186 \end{alltt} 187 188 \noindent 189 assuming {\tt a} and {\tt low} are not the 190 same reference (reverse the order of the 191 functions if they are the same reference.) 192 193 {\tt zsplit} copies the lowest {\tt b} bits 194 of {\tt a} to {\tt low}, and the rest of the 195 bits to {\tt high}, with the lowest {\tt b} 196 removesd. For example, if $a = 1010101111_2$, 197 then $high = 101010_2$ and $low = 1111_2$ 198 after calling {\tt zsplit(high, low, a, 4)}. 199 200 {\tt zsplit} is especially useful in 201 divide-and-conquer algorithms. 202 203 204 \newpage 205 \section{Bit manipulation} 206 \label{sec:Bit manipulation} 207 208 209 The function 210 211 \begin{alltt} 212 void zbset(z_t r, z_t a, size_t bit, int mode); 213 \end{alltt} 214 215 \noindent 216 is used to manipulate single bits in {\tt a}. It will 217 copy {\tt a} into {\tt r} and then, in {\tt r}, either 218 set, clear, or flip, the bit with the index {\tt bit} 219 — the least significant bit has the index 0. The 220 action depend on the value of {\tt mode}: 221 222 \begin{itemize} 223 \item 224 $mode > 0$ ($+1$): set 225 \item 226 $mode = 0$ ($0$): clear 227 \item 228 $mode < 0$ ($-1$): flip 229 \end{itemize} 230 231 232 \newpage 233 \section{Bit test} 234 \label{sec:Bit test} 235 236 libzahl provides a function for testing whether a bit 237 in a big integer is set: 238 239 \begin{alltt} 240 int zbtest(z_t a, size_t bit); 241 \end{alltt} 242 243 \noindent 244 it will return 1 if the bit with the index {\tt bit} 245 is set in {\tt a}, counting from the least significant 246 bit, starting at zero. 0 is returned otherwise. The 247 sign of {\tt a} is ignored. 248 249 We can think of this like so: consider 250 251 $$ \lvert a \rvert = \sum_{i = 0}^\infty k_i 2^i,~ k_i \in \{0, 1\}, $$ 252 253 \noindent 254 {\tt zbtest(a, b)} returns $k_b$. Equivalently, we can 255 think that {\tt zbtest(a, b)} return whether $b \in B$ 256 where $B$ is defined by 257 258 $$ \lvert a \rvert = \sum_{b \in B} 2^b,~ B \subset \textbf{Z}_+, $$ 259 260 \noindent 261 or as right-shifting $a$ by $b$ bits and returning 262 whether the least significant bit is set. 263 264 {\tt zbtest} always returns 1 or 0, but for good 265 code quality, you should avoid testing against 1, 266 rather you should test whether the value is a 267 truth-value or a falsehood-value. However, there 268 is nothing wrong with depending on the value being 269 restricted to being either 1 or 0 if you want to 270 sum up returned values or otherwise use them in 271 new values. 272 273 274 \newpage 275 \section{Connectives} 276 \label{sec:Connectives} 277 278 libzahl implements the four basic logical 279 connectives: and, or, exclusive or, and not. 280 The functions for these are named {\tt zand}, 281 {\tt zor}, {\tt zxor}, and {\tt znot}, 282 respectively. 283 284 The connectives apply to each bit in the 285 integers, as well as the sign. The sign is 286 treated as a bit that is set if the integer 287 is negative, and as cleared otherwise. For 288 example (integers are in binary): 289 290 \begin{alltt} 291 zand(r, a, b) zor(r, a, b) 292 a = +1010 (input) a = +1010 (input) 293 b = -1100 (input) b = -1100 (input) 294 r = +1000 (output) r = -1110 (output) 295 296 zxor(r, a, b) znot(r, a) 297 a = +1010 (input) a = +1010 (input) 298 b = -1100 (input) r = -0101 (output) 299 r = -0110 (output) 300 \end{alltt} 301 302 Remember, in libzahl, integers are represented 303 with sign and magnitude, not two's complement, 304 even when using these connectives. Therefore, 305 more work than just changing the name of the 306 called function may be required when moving 307 between big integer libraries. Consequently, 308 {\tt znot} does not flip bits that are higher 309 than the highest set bit, which means that 310 {\tt znot} is nilpotent rather than self dual. 311 312 Below is a list of the value of {\tt a} when 313 {\tt znot(a, a)} is called repeatedly. 314 315 \begin{alltt} 316 10101010 317 -1010101 318 101010 319 -10101 320 1010 321 -101 322 10 323 -1 324 0 325 0 326 0 327 \end{alltt}