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} |