2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

bitfieldを利用して"1"を数える。

Last updated at Posted at 2016-10-15
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

2
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?