Reputation: 6494
static uint32_t get_num(void);
uint32_t get_count(unsigned int mask)
{
uint8_t i = 0;
uint32_t count = 0;
while (i < get_num())
{
if (mask & (1 << i++))
count++;
}
return count;
}
In this code, what would be more safe (1L << i++)
or (1UL << i++)
?
Upvotes: 0
Views: 138
Reputation: 12263
If you just want to count the 1-bits in an uint and use gcc, you should have a look at the builtin functions (here: int __builtin_popcount (unsigned int x)
). These can be expected to be highly optimized and even use special instructions of the CPU where available. (one could very wenn test for gcc).
However, not sure what get_num()
would yield - it just seems not to depend on mask
, so its output can be used to limit the result of popcount.
The following uses a loop and might be faster than a parallel-add tree on some architectures (one should profile both versions if timing is essential).
unsigned popcount(uint32_t value, unsigned width)
{
unsigned cnt = 0; // actual size intentionally by arch
if ( width < 32 )
value &= (1UL << width) - 1; // limit to actual width
for ( ; value ; value >>= 1 ) {
cnt += value & 1U; // avoids a branch
}
return cnt;
}
Note the width is passed to the function.
On architectures with < 32 bits (PIC, AVR, MSP430, etc.) specialized versions will gain much better results than a single version.
Upvotes: 0
Reputation: 181459
An unsigned operand is a bit safer because only then is the behavior of all the shifts defined when get_num()
returns the number of bits in that operand's type. If unsigned long
is wider than unsigned int
then UL
is slightly safer than just U
, but only for accommodating get_num()
results that aren't valid anyway.
Safer yet, however, is this:
uint32_t get_count(uint32_t mask)
{
uint8_t num = get_num();
if (num == 0) return 0;
/* mask off the bits we don't want to count */
mask &= ~((uint32_t) 0) >> ((num < 32) ? (32 - num) : 0);
/* count the remaining 1 bits in mask, leaving the result in mask */
mask = (mask & 0x55555555) + ((mask & 0xaaaaaaaa) >> 1);
mask = (mask & 0x33333333) + ((mask & 0xcccccccc) >> 2);
mask = (mask & 0x0f0f0f0f) + ((mask & 0xf0f0f0f0) >> 4);
mask = (mask & 0x00ff00ff) + ((mask & 0xff00ff00) >> 8);
mask = (mask & 0x0000ffff) + ((mask & 0xffff0000) >> 16);
return mask;
}
Upvotes: 1