| bit-operations.tex - libzahl - big integer library | |
| git clone git://git.suckless.org/libzahl | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| 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} |