Article View: comp.lang.c.moderated
Article #2538Re: Efficiency Question : bits vs. bytes (or anything else, for that matter)
From: telnet user
Date: Sat, 06 Apr 1996 14:51
Date: Sat, 06 Apr 1996 14:51
107 lines
3757 bytes
3757 bytes
Richard A. O'Keefe (ok@cs.rmit.edu.au) wrote:
: [ bitset operations ]
: Note the following trick for walking through an array of unsigned longs,
: processing each bit. It assumes that each bit in the array is used.
: void walk_bits_in_ulongs(
: unsigned long const *base,
: unsigned nwords,
: void (*f)(unsigned /*bitno*/, int /*bit*/)
: ) {
: unsigned bitno;
: unsigned i;
: for (bitno = 0, i = 0; i < nwords; i++) {
: unsigned long const word = base[i];
: unsigned long mask;
>>> if (!word) continue;
: for (mask = 1; mask != 0; mask <<= 1, bitno++)
: f(bitno, (word & mask) != 0);
: }
: }
: Again, the saving comes about because we are NOT fetching bits in a
: true ELEMENT-WISE fashion, but in groups.
The above trick inserted (>>>) is a good one to remember when working
with bitsets. On many CPUs, the above check is essentially 'free',
since it just depends on a condition flag that gets set when the value
is loaded anyway.
Intersection and union, of course, are very efficient (just use & and
|) in terms of bitsets.
Of course, you can do even better than that. I timed a similar
algorithm on a wide variety of architectures, and the following
algorithm won for finding the set bit in a bitfield (or giving an
error if more than one is set):
static int get_single(unsigned int *, bv) {
int i, res = -1;
for (i = 0; i < NUM_BITVEC_INTS; i++) {
if (bv[i]) { /* test 16 bits at a time! */
if (res != -1) return -1;
res = i;
}
}
if (res == -1) return res;
i = bv[res];
/* Binary search for the set bit, unrolled for speed. */
if (i & 0x0000ffff) {
if (i & 0xffff0000)
return -1;
} else {
i >>= 16;
res += 16;
}
if (i & 0x00ff) {
if (i & 0xff00)
return -1;
} else {
i >>= 8;
res += 8;
}
if (i & 0x0f) {
if (i & 0xf0)
return -1;
} else {
i >>= 4;
res += 4;
}
if (i & 0x3) {
if (i & 0xc)
return -1;
} else {
i >>= 2;
res += 2;
}
if (i & 0x1) {
if (i & 0x2)
return -1;
return res;
} else {
return res + 1;
}
}
If you're wondering why the shifts are there, remember shifts are
cheap, and it turns out the full 32 bit integer constants (like
0xaaaaaaaa) appear to be rather slow on many RISC CPUs, so it's faster
to reduce the problem to one involving smaller constants.
Similar tricks for counting bits exist; I think the C FAQ has some of them.
---------------------------------------------------------------------------
Tim Hollebeek | Disclaimer :=> Everything above is a true statement,
Electron Psychologist | for sufficiently false values of true.
Princeton University | email: tim@wfn-shop.princeton.edu
----------------------| http://wfn-shop.princeton.edu/~tim (NEW! IMPROVED!)
Technical Details
Message-ID:
<4k60ec$acm@solutions.solon.com>Path:
arc1-ca.pugleaf.net!solon.com!not-for-mailReferences:
<4jbciv$2kk@solutions.solon.com> <4jr741$h8l@solutions.solon.com> <4jttc7$3hu@solutions.solon.com> <4k1qp0$5n8@solutions.solon.com>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!solon.com!not-for-mail From: tim@franck.Princeton.EDU (telnet user) Newsgroups: comp.lang.c.moderated Subject: Re: Efficiency Question : bits vs. bytes (or anything else, for that matter) Date: 6 Apr 1996 08:51:56 -0600 Organization: Princeton University Sender: clc@solutions.solon.com Approved: clc@solutions.solon.com Message-ID: <4k60ec$acm@solutions.solon.com> References: <4jbciv$2kk@solutions.solon.com> <4jr741$h8l@solutions.solon.com> <4jttc7$3hu@solutions.solon.com> <4k1qp0$5n8@solutions.solon.com> Reply-To: tim@wagner.Princeton.EDU NNTP-Posting-Host: solutions.solon.com X-Newsreader: TIN [version 1.2 PL2]