bit_counter.c
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
///////////////////////////////////////
// TYPE DEFINITION
/////////////////////
typedef struct ST_32_BITFIELD
{
unsigned char lsb : 1;
long int rest : 30;
unsigned char msb : 1;
}ST_32_BITFIELD;
typedef union UN_UL_VAL
{
ST_32_BITFIELD st_32bitfield;
long int value;
} UN_UL_VAL;
typedef enum EM_COUNT_METHOD
{
EM_COUNT_METHOD_BUNKATSU_TOUCHI,
EM_COUNT_METHOD_BITFIELD,
EM_COUNT_METHOD_MAX
} EM_COUNT_METHOD;
///////////////////////////////////////
// MACRO & DEFINITION
/////////////////////
# define STR_BUNKATSU_TOUCHI "BUNKATSU_TOUCHI"
# define STR_BITFIELD "BITFIELD"
# define STR_UNKNOWN "Unknown"
///////////////////////////////////////
// Internal functions
/////////////////////
static void showUsage(void);
static unsigned int count_by_bunkatsu_touchi_method(unsigned int);
static unsigned int count_by_bitfield(unsigned int);
static char* methodToString(EM_COUNT_METHOD);
static void showUsage(void)
{
printf("USAGE: ./a.out\n");
printf("\t -c : input unsigned int value in decimal format. (mandatory argument).\n");
printf("\t -m : select count method.\n");
printf("\t 0:bunkatsu(default) 1:bitf\n");
}
//単純にカウントする場合は、分割統治法だとか、popcountだとかを強く推奨。
//これは分割統治法での例です。原典はPage下記に記載させて頂いております。
static unsigned int count_by_bunkatsu_touchi_method(unsigned int x)
{
unsigned int _x = x;
_x = _x - ((_x >> 1) & 0x55555555);
_x = (_x & 0x33333333) + ((_x >> 2) & 0x33333333);
_x = (_x + (_x >> 4)) & 0x0f0f0f0f;
_x = _x + (_x >> 8);
_x = _x + (_x >> 16);
_x = _x & 0x0000003F;
return _x;
}
//アプリの特性上、カウントついでに
//ごちょごちょする必要があるなら、こういうやり方もある。
//ただし、このコードはカウントすることしか書いてないですヨ。
static unsigned int count_by_bitfield(unsigned int x)
{
UN_UL_VAL un_val = {0};
un_val.value = x;
long int count = 0;
for(int i = 0; i < 32; i++, un_val.value >>= 1)
{
// printf("lsb:%d value=%ld \n",un_val.st_32bitfield.lsb, un_val.value);
if(1 == un_val.st_32bitfield.lsb)
{
count++;
}
}
return count;
}
static char* methodToString(EM_COUNT_METHOD _em_method)
{
char* result = NULL;
switch(_em_method)
{
case(EM_COUNT_METHOD_BUNKATSU_TOUCHI):
{
result = STR_BUNKATSU_TOUCHI;
break;
}
case(EM_COUNT_METHOD_BITFIELD):
{
result = STR_BITFIELD;
break;
}
default:
{
result = STR_UNKNOWN;
}
}
return result;
}
int main(int argc,char *argv[]) {
long int target = 0;
EM_COUNT_METHOD em_method = EM_COUNT_METHOD_BUNKATSU_TOUCHI;//default
int initCompFlag = 0;
unsigned int countResult = 0;
if((argc < 2) || (0 == argc%2))
{
showUsage();
exit(0);
}
else
{
for (int i=1; i < argc; i++)
{
if(0 == strncmp(argv[i], "-c", 4))
{
target = strtol(argv[++i], NULL, 10);
initCompFlag = 1;
}
else if(0 == strncmp(argv[i], "-m", 4))
{
em_method = strtol(argv[++i], NULL, 10);
}
else
{
showUsage();
exit(0);
}
}
//confirm initialization status.
if(1 == initCompFlag)
{
printf("evaluation target value is = %ld\n", target);
printf("count method is = %s.\n", methodToString(em_method));
if((EM_COUNT_METHOD_BUNKATSU_TOUCHI != em_method) &&
(EM_COUNT_METHOD_BITFIELD != em_method))
{
printf("method:%d is invalid.\n", em_method);
showUsage();
exit(0);
}
}
else //including : 0 == init_comp_flag
{
showUsage();
exit(0);
}
}
switch(em_method)
{
case(EM_COUNT_METHOD_BUNKATSU_TOUCHI):
{
countResult = count_by_bunkatsu_touchi_method(target);
break;
}
case(EM_COUNT_METHOD_BITFIELD):
{
countResult = count_by_bitfield(target);
break;
}
default:
{
printf("method:%d is invalid.\n", em_method);
showUsage();
exit(0);
}
}
printf("# of true bit is %u\n",countResult);
return EXIT_SUCCESS;
}
こんな感じでどうでしょう。。。
注意として、bitfield構造体を定義するときに、1bitの部分(本例だと、msb, lsb)を符号有り型で定義すると、
評価するときにマイナスの値になってしまうので、countが増えないプログラムになります。
Oct/18/2016:
※ご指摘がありましたので、分割統治法でのカウント方法サンプルコードと、ごちゃごちゃ言い訳コメントもつけてみました。
分割統治法のコードをご紹介してくださっているURL:https://www.kaeruspoon.net/articles/720