The FLINT/C package contains functions that allow the built-in bitwise C operators &, |, and ^ to be used for the type CLINT as well. However, before we program these functions we would like to understand what their implementation will net us.
From a mathematical viewpoint we are looking at relations of the generalized Boolean functions f : { 0, 1 }k → { 0, 1 } that map a k-tuple (x1,..., xk) Î { 0, 1 }k to the value 0 or 1. The effect of a Boolean function is usually presented in the form of a table of values such as that shown in Table 7.1.
|
x1 |
x2 |
... |
xk |
f (x1, ..., xk) |
|---|---|---|---|---|
|
0 |
0 |
... |
0 |
0 |
|
1 |
0 |
... |
0 |
1 |
|
0 |
1 |
... |
0 |
0 |
|
⋮ |
⋮ |
⋮ |
⋮ |
⋮ |
|
1 |
1 |
... |
1 |
1 |
For the bitwise relations between CLINT types we first regard the variables as bit vectors (x1, ..., xn), and furthermore, the function values of the Boolean functions will be formed into a sequence. Thus we have functions
that map n-bit variables
:= (
) and
:= (
) by
with fi (
) := f (
), again to an n-bit variable (x1, ..., xn), which is then interpreted as a number of type CLINT.
Decisive for the operation of the function
is the definition of the partial functions fi, each of which is defined in terms of a Boolean function f. For the CLINT functions and_l(), or_l(), and xor_l() the Boolean functions that are implemented are defined as in Tables 7.2–7.4.
|
x1 |
x2 |
f (x1, x2) |
|---|---|---|
|
0 |
0 |
0 |
|
0 |
1 |
0 |
|
1 |
0 |
0 |
|
1 |
1 |
1 |
|
x1 |
x2 |
f (x1, x2) |
|---|---|---|
|
0 |
0 |
0 |
|
0 |
1 |
1 |
|
1 |
0 |
1 |
|
1 |
1 |
1 |
|
x1 |
x2 |
f (x1, x2) |
|---|---|---|
|
0 |
0 |
0 |
|
0 |
1 |
1 |
|
1 |
0 |
1 |
|
1 |
1 |
0 |
The implementations of these Boolean functions in the three C functions and_l(), or_l(), and xor_l() do not actually proceed bitwise, but process the digits of CLINT variables by means of the standard C operators &, |, and ^. Each of these functions accepts three arguments of CLINT type, where the first two are the operands and the last the result variable.
void
and_l (CLINT a_l, CLINT b_l, CLINT c_l)
{
CLINT d_l;
clint *r_l, *s_l, *t_l;
clint *lastptr_l;
if (DIGITS_L (a_l) < DIGITS_L (b_l))
{
r_l = LSDPTR_L (b_l);
s_l = LSDPTR_L (a_l);
lastptr_l = MSDPTR_L (a_l);
}
else
{
r_l = LSDPTR_L (a_l);
s_l = LSDPTR_L (b_l);
lastptr_l = MSDPTR_L (b_l);
}
t_l = LSDPTR_L (d_l); SETDIGITS_L (d_l, DIGITS_L (s_l - 1));
while (s_l <= lastptr_l)
{
*t_l++ = *r_l++ & *s_l++;
}
cpy_l (c_l, d_l); }
void
or_l (CLINT a_l, CLINT b_l, CLINT c_l)
{
CLINT d_l;
clint *r_l, *s_l, *t_l;
clint *msdptrr_l;
clint *msdptrs_l;
if (DIGITS_L (a_l) < DIGITS_L (b_l)) { r_l = LSDPTR_L (b_l); s_l = LSDPTR_L (a_l); msdptrr_l = MSDPTR_L (b_l); msdptrs_l = MSDPTR_L (a_l); } else { r_l = LSDPTR_L (a_l); s_l = LSDPTR_L (b_l); msdptrr_l = MSDPTR_L (a_l); msdptrs_l = MSDPTR_L (b_l); } t_l = LSDPTR_L (d_l); SETDIGITS_L (d_l, DIGITS_L (r_l - 1));
while (s_l <= msdptrs_l)
{
*t_l++ = *r_l++ | *s_l++;
}
while (r_l <= msdptrr_l)
{
*t_l++ = *r_l++;
}
cpy_l (c_l, d_l);
}
void
xor_l (CLINT a_l, CLINT b_l, CLINT c_l)
{
CLINT d_l;
clint *r_l, *s_l, *t_l;
clint *msdptrr_l;
clint *msdptrs_l;
if (DIGITS_L (a_l) < DIGITS_L (b_l))
{
r_l = LSDPTR_L (b_l);
s_l = LSDPTR_L (a_l);
msdptrr_l = MSDPTR_L (b_l);
msdptrs_l = MSDPTR_L (a_l);
}
else
{
r_l = LSDPTR_L (a_l);
s_l = LSDPTR_L (b_l);
msdptrr_l = MSDPTR_L (a_l);
msdptrs_l = MSDPTR_L (b_l);
}
t_l = LSDPTR_L (d_l);
SETDIGITS_L (d_l, DIGITS_L (r_l - 1));
while (s_l <= msdptrs_l)
{
*t_l++ = *r_l++ ^ *s_l++;
}
while (r_l <= msdptrr_l)
{
*t_l++ = *r_l++;
}
cpy_l (c_l, d_l);
}
The function and_l() can be used to reduce a number a modulo a power of two 2k by setting a CLINT variable a_l to the value a, a CLINT variable b_l to the value 2k − 1, and executing and_l(a_l, b_l, c_l). However, this operation executes faster with the function mod2_l() created for this purpose, which takes into account that the binary representation of 2k − 1 consists exclusively of ones (see Section 4.3).
|
Team-Fly |