# libzahl

big integer library
git clone git://git.suckless.org/libzahl

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}