C言語——1つの数字の2進数の中で1の個数を求めます

2244 ワード

プログラムを書いて指定した数字のバイナリの中の1の個数を印刷して、例えば:15(0000 1111)出力4
次の3つの方法があります.
①型2による2(%2、/2)の除去方法
num%2-バイナリの最後のビットを取り出します
num/2-右シフトバイナリの最後のビットを削除
whileサイクルにより,バイナリの最後のビット数を順次取り出して1であるか否かを判断し,1であればcount++であり,while(num)はnumが0になったときのみループが終了する.
問題:テスト-1でバグが発生し、-1のバイナリには32個の1があるはずですが、出力は0です.−1をコードに持ち込むと−1%2=0でcountは増加せず,その後−1/2=0でループが終了するため,countの値は0に出力される.
解決策:変数numのデータ型をunsigned int(符号なし整数型)に変更すると、正の整数型の最大値を表すので、num=-1の場合、バイナリが32個1の正数を表し、ループで正しい個数を出力できます.
コード1:
#include 

int main()
{
	int num = 15;
      //unsigned int num = -1;
      //         bug,          
        int count = 0;//  
	while (num)
	{
		if (num % 2 == 1)
			count++;
		num = num / 2;
	}
	printf("    1    :%d
",count); return 0; }

②右シフトオペレータ(>>)、ビット単位、オペレータ(&)で実現
Example:num=10(1010)の場合、num>>iを右に移動し、iビットをバイナリで右に移動します.
//i=0,num>>0,0ビット右シフト,このとき(1010)&(0001)=0
//i=1,num>>1,右に1ビットシフトした場合(0101)&(0001)=1,count++
//i=2,num>>2,右に2ビットシフトし、このとき(0010)&(0001)=0
//i=3,num>>3,右に3ビットシフトし、このとき(0001)&(0001)=1,count++
……
バイナリは32ビットであるため,ループは32回実行して終了し,countは2となる.
欠点:効率が悪く、32回循環しなければならない
コード2(最適化1):
#include 

int count_one_bits(unsigned int value)
{
	int count = 0;
	int i = 0;
	for (i = 0; i < 32; i++)
	{
		if ((value>>i)&1 == 1)
			count++;
	}
	return count; //   1    
}
int main()
{
	int number = 0;
	printf("Input:");
	scanf("%d",&number);
	printf("%d
",count_one_bits(number)); return 0; }

③ビットとオペレータ(&)の巧みな演算により実現
Example:num=15の場合、
1//num&(num-1)=(1111)&(1110)=(1110)   
2//num&(num-1)=(1110)&(1101)=(1100)  
3//num&(num-1)=(1100)&(1011)=(1000)  
4//num&(num-1)=(1000)&(0111)=0、ループ停止.合計4回whileサイクルを実行します.
実行するたびに右端の1を削除し,so~ループを何回か実行するといくつかの1があることがわかる.
効率的!いくつか1つで何回か処理します
コード3(最適化2):
#include 

int main()
{
	int num = 15;
	int count = 0;
	int i = 0;
	while (num)
	{
          num = num&(num - 1);
          count++;
 	}
	printf("    1    :%d
",count); return 0; }