G
Guest
Frederick said:Richard Heathfield posted:Your solution doesn't appear to cope with integers wider than 21 bits,
for a start. Secondly, it doesn't cope with integers that are /fewer/
than 21 bits wide! Thirdly, it could conceivably be counting "padding
bits", bits that do not contribute to the value of the integer."If the value of the right operand is negative or is greater
than or equal to the width in bits of the promoted left operand, the
behavior is undefined."
I meant something more along the following lines. Do compilers nowadays
optimise away Bitwise-AND operations when one of the operands is known to
be 0 at compile-time?
/* Macro: QUANT_BITS_SET
This macro determines the quantity of bits which
are set in an integer expression whose signedness
is unsigned.
The typedef, "BitsSetType", specifies the unsigned
integer type which is to be used for processing.
Before processing takes place, the argument is
converted to BitsSetType.
This macro should work with unsigned integer types
as wide as 1024 bits.
NB: This macro evaluates its argument more than once.
*/
typedef unsigned BitsSetType;
#define IMAX_BITS(m) (\
(m) /((m)%0x3fffffffL+1) /0x3fffffffL \
%0x3fffffffL *30 \
+ (m)%0x3fffffffL /((m)%31+1)/31%31*5 \
+ 4 \
- 12 / ((m)%31+3) )
#define MASK_ZERO_IF_OVER(shift_left_by) (\
shift_left_by < IMAX_BITS((BitsSetType)-1) \
? (BitsSetType)1 << shift_left_by \
: (BitsSetType)0 )
#define QUANT_BITS_SET_RAW(x) (\
!!((x)&(BitsSetType)1) + !!((x)&(BitsSetType)1<<1) \
+!!((x)&(BitsSetType)1<<2) + !!((x)&(BitsSetType)1<<3) \ ....
+!!((x)&(BitsSetType)1<<14) +!!((x)&(BitsSetType)1<<15) \
+!!((x)&MASK_ZERO_IF_OVER(16))+!!((x)&MASK_ZERO_IF_OVER(17))\ ....
+!!((x)&MASK_ZERO_IF_OVER(1022))+!!((x)&MASK_ZERO_IF_OVER(1023)))
#define QUANT_BITS_SET(x) QUANT_BITS_SET_RAW( ((BitsSetType)(x)) )
#include <stdio.h>
int main(void)
{
/* Let's make an array of length 4 */
int arr[QUANT_BITS_SET(17)];
printf("%u",(unsigned)(sizeof arr/sizeof*arr));
}
The codes prints 2 on my system, but you get the idea...
You know, you could make that a /lot/ shorter, and I know you're so
very fond of IMAX_BITS, but it's unnecessary and without benefits here.
I haven't verified if everything is strictly portable in this version,
but if not, it should serve as at least a starting point.
#define COUNT_8(x) (!!((x) & 0x80)) + (!!((x) & 0x40)) \
+ (!!((x) & 0x20)) + (!!((x) & 0x10)) \
+ (!!((x) & 0x08)) + (!!((x) & 0x04)) \
+ (!!((x) & 0x02)) + (!!((x) & 0x01))
#define COUNT_16(x) COUNT_8 ((x) & 0xFFULL) \
+ COUNT_8 ((x) >> 8)
#define COUNT_32(x) COUNT_16 ((x) & 0xFFFFULL) \
+ COUNT_16 ((x) >> 16)
#define COUNT_64(x) COUNT_32 ((x) & 0xFFFFFFFFULL) \
+ COUNT_32 ((x) >> 32)
#define COUNT_128(x) COUNT_64 ((x) & 0xFFFFFFFFFFFFFFFFULL) \
+ COUNT_64 ((x) >> 60 >> 4)
#define COUNT_256(x) COUNT_128(((1ULL << 60 << 60 << 8) - 1) & (x)) \
+ COUNT_128( (x) >> 60 >> 60 >> 8)
#define COUNT_512(x) COUNT_256(((1ULL << 60 << 60 << 60 << 60 << 16) -
1) & (x)) \
+ COUNT_256( (x) >> 60 >> 60 >> 60 >> 60 >> 16)
#define COUNT_1024(x)COUNT_512(((1ULL << 60 << 60 << 60 << 60 << 60 <<
60 << 60 << 60 << 32) - 1) & (x)) \
+ COUNT_512( (x) >> 60 >> 60 >> 60 >> 60 >> 60#define COUNT(x) COUNT_1024((unsigned long long) x)
You'll need to fix the line wrapping a bit, but it should be obvious
where. (Maybe uintmax_t would be better than unsigned long long.)