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:
②右シフトオペレータ(>>)、ビット単位、オペレータ(&)で実現
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):
③ビットとオペレータ(&)の巧みな演算により実現
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):
次の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;
}