allow ffs & co. a binary search
Hans Petter Selasky
hps at selasky.org
Sun Jun 7 07:02:33 UTC 2015
On 06/07/15 02:13, Erich Dollansky wrote:
> Hi,
>
> I stumbled these days over the functions to find the first or last bit
> set. They are currently written like this:
>
> /*
> * Find First Set bit
> */
> int
> ffs(int mask)
> {
> int bit;
>
> if (mask == 0)
> return (0);
> for (bit = 1; !(mask & 1); bit++)
> mask = (unsigned int)mask >> 1;
> return (bit);
> }
>
> With other words, the program loops until it finds what it searches for.
>
> Why not do it the binary way?
>
> int res;
>
> res = 0;
> IF (Number != 0) THEN
> res = 1;
> IF ((Number & 0xFFFFFFFF00000000) != 0) THEN
> Number = Number & 0xFFFFFFFF00000000;
> res = res + 32;
> END;
> IF ((Number & 0xFFFF0000FFFF0000) != 0) THEN
> Number = Number & 0xFFFF0000FFFF0000;
> res = res + 16;
> END;
> IF ((Number & 0xFF00FF00FF00FF00) != 0) THEN
> Number = Number & 0xFF00FF00FF00FF00;
> res = res + 8;
> END;
> IF ((Number & 0xF0F0F0F0F0F0F0F0) != 0) THEN
> Number = Number & 0xF0F0F0F0F0F0F0F0;
> res = res + 4;
> END;
> IF ((Number & 0xCCCCCCCCCCCCCCCC) != 0) THEN
> Number = Number & 0xCCCCCCCCCCCCCCCC;
> res = res + 2;
> END;
> IF ((Number & 0xAAAAAAAAAAAAAAAA) != 0) THEN
> Number = Number & 0xAAAAAAAAAAAAAAAA;
> res = res + 1;
> END;
> END;
> return res;
>
> If you like the binary way I could give you the sources for the
> complete family following your style to replace the older functions.
>
Hi Erich,
I think this is not the fastest way to do it. You first find the LSB,
then you do a sumbits, which doesn't have any conditionals IF/ELSE and
performs better with the CPU pipeline. I think the software ffs() is
only used for platforms which doesn't have a hardware version btw:
From my libmbin:
> uint8_t
> mbin_sumbits32(uint32_t val)
> {
> #if 0
> uint8_t t = 0;
>
> while (val) {
> if (val & 1)
> t++;
> val >>= 1;
> }
> return (t);
> #else
> val = ((val & (1U * 0xAAAAAAAAU)) / 2U) + (val & (1U * 0x55555555U));
> val = ((val & (3U * 0x44444444U)) / 4U) + (val & (3U * 0x11111111U));
> val = ((val & (15U * 0x10101010U)) / 16U) + (val & (15U * 0x01010101U));
> val = ((val & (255U * 0x01000100U)) / 256U) + (val & (255U * 0x00010001U));
> val = ((val & (65535U * 0x00010000U)) / 65536U) + (val & (65535U * 0x00000001U));
> return (val);
> #endif
> }
> uint32_t
> mbin_lsb32(uint32_t val)
> {
> return ((~(val - 1)) & val);
> }
int ffs(int value)
{
int retval = mbin_sumbits32(mbin_lsb32(value) - 1);
if (retval == 32)
retval = 0;
else
retval++;
return (retval);
}
--HPS
More information about the freebsd-hackers
mailing list