すいませんputcharx>>iではなく1になっていたのが原因でした。
putchar(((x>>i)&1U)?'1':'0');の部分がよく理解できません。
例えば55という数字はどのように動かされて
2進数に変換されるのが教えてください
int count_bits(unsigned x) { int count=0; while(x){ if(x&1U)count++; x>>=1; } return (count); } int int_bits(void) { return(count_bits(~0U)); } void print_bits(unsigned x) { int i; for(i=int_bits()-1;i>=0;i--) putchar(((x>>i)&1U)?'1':'0'); } int main(void){ unsigned nx; printf("type non negative"); scanf("%u",&nx); print_bits(nx); putchar('\n'); return 0; } コード
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
ベストアンサー
【普通の解説】
※ 宗教的な理由で、unsigned
は全てunsigned int
と記述しています。
まず、int_bits()
がunsigned int
におけるbitsの数になることは理解できているでしょうか?もし、unsigned int
が32bitsならint_bits()
は32を返します(ぶっちゃけ、sizeof(unsigned int) * CHAR_BIT
でもいい気がするのですが)。次に、for(i=int_bits()-1;i>=0;i--)
の部分ですが、i
について、31(-1しているので32ではありません)から0までforループで回すという意味です。あとはforループの中身を見ればわかるはずです。
forループの中身ですが、x>>i
が何をしているかというと、x
をi
分だけシフトするという意味です。たとえば、xが55という数字の場合、2進数では下記になります。
x: 0000 0000 0000 0000 0000 0000 0011 0111
※ わかりやすいように、4bits毎にスペースで区切っています。
そして、iは31から始まりますので、まずは31個分左にシフトし、下記になります。
x >> 31: 0000 0000 0000 0000 0000 0000 0000 0000
全て0になりました。iが31から6までは同じようにすべて0になります。ビットが一切立ってないので、ここまでは0ということです。そして、0は偽なので三項演算子の部分は'0'が返り、0が表示されます。ではiが5の場合はどうなるかというと、
x >> 5: 0000 0000 0000 0000 0000 0000 0000 0001
と、最後に一つだけ残ります。次に1U
はなにかというと下記のようになっています。
1U: 0000 0000 0000 0000 0000 0000 0000 0001
この二つを&
で演算すれば、
(x >> 5)&1U: 0000 0000 0000 0000 0000 0000 0000 0001
となり、つまり、左から6番目(5番目ではありません。判断するのはi+1番目です)のビットが立っているかがわかると言うことです。そして、1は真なので三項演算子の部分は'1'が返り、1が表示されます。同じようにi
が4の場合は、
x >> 4: 0000 0000 0000 0000 0000 0000 0000 0011
1U: 0000 0000 0000 0000 0000 0000 0000 0001
(x >> 4)&1U: 0000 0000 0000 0000 0000 0000 0000 0001
となり、5番目のビットが立っていると判断できます。では3の場合はどうでしょうか?
x >> 3: 0000 0000 0000 0000 0000 0000 0000 0110
1U: 0000 0000 0000 0000 0000 0000 0000 0001
(x >> 3)&1U: 0000 0000 0000 0000 0000 0000 0000 0000
おお、0になりますね。つまり4番目のビットは立っていない、なので0なのです。あとは同じように、0までするだけです。
x >> 2: 0000 0000 0000 0000 0000 0000 0000 1101
1U: 0000 0000 0000 0000 0000 0000 0000 0001
(x >> 2)&1U: 0000 0000 0000 0000 0000 0000 0000 0001 # 3番目はビットが立ている
x >> 1: 0000 0000 0000 0000 0000 0000 0001 1011
1U: 0000 0000 0000 0000 0000 0000 0000 0001
(x >> 1)&1U: 0000 0000 0000 0000 0000 0000 0000 0001 # 2番目はビットが立ている
x >> 0: 0000 0000 0000 0000 0000 0000 0011 0111
1U: 0000 0000 0000 0000 0000 0000 0000 0001
(x >> 0)&1U: 0000 0000 0000 0000 0000 0000 0000 0001 # 1番目はビットが立ている
結果、00000000000000000000000000110111が表示されることがわかると思います。
【おまけ】
汎用性を持たせてみました。
C
1#include <stdio.h> 2#include <stdlib.h> 3#include <stdint.h> 4#include <limits.h> 5 6#define UINTMAX_BITS_SIZE (sizeof(uintmax_t) * CHAR_BIT) 7#define print_bits(x) print_bits_n((x), sizeof(x) * CHAR_BIT) 8 9int count_bits(uintmax_t bits); 10void print_bits_n(uintmax_t bits, int width); 11 12int main(void) 13{ 14 unsigned int nx; 15 printf("type positive number (%u..%u): ", 0, UINT_MAX); 16 if (scanf("%u",&nx) != 1) { 17 printf("not number"); 18 exit(1); 19 } 20 21 print_bits(nx); 22 putchar('\n'); 23 printf("%d\n", count_bits(nx)); 24 25 return 0; 26} 27 28int count_bits(uintmax_t bits) 29{ 30 for (int i = 1; i < UINTMAX_BITS_SIZE; i <<= 1) { 31 uintmax_t mask = (UINTMAX_C(1) << i) - 1; 32 for (int j = (i << 1); j < UINTMAX_BITS_SIZE; j <<= 1) { 33 mask += mask << j; 34 } 35 bits = (bits & mask) + (bits >> i & mask); 36 } 37 return (int)bits; 38} 39 40void print_bits_n(uintmax_t bits, int width) 41{ 42 for (int i = width - 1; i >= 0; i--) { 43 putchar(bits & (UINTMAX_C(1) << i) ? '1' : '0'); 44 } 45}
特徴は下記の通りです。
- 参考サイトのバージョン5を汎用化。いくらでも大きく、かつ、unsignedで処理が可能に。(ただ、高速を目指すなら、mask値はテーブル化やメモ化すべきだろうが、面倒だったのでそこまではしてない)
- unsigned intの大きさが16bitsでも、32bitsでも、64bitsでも、128bitsでも、256bitsでもいくらでも大きくてもたぶん大丈夫。
- 表示は普通に上からビット演算することで、単純化。ただし、速くなるかどうかはわからない。 (あらかじめテーブル作ったら速くなりそう)
- 符号有り整数で負の値を渡すと、カウントはうまくいかないので、unsignedでキャストしてから、渡してね。unsignedなら正しく暗黙的キャストするので何でもOK。
- C99にちゃんと対応していないコンパイラでは通らない。(GCCとClangで確認済み、Visual Studioは未確認)
> katoyさん
参考サイトのバージョン4をunsignedにしたり、汎用化するのは私には無理でした。ごめんなさい。代わりにバージョン5で対応したので、許してください。
投稿2015/08/29 23:38
編集2015/08/30 00:22総合スコア21735
0
c
1#include <stdio.h> 2 3// https://msdn.microsoft.com/ja-jp/library/s3f49ktz.aspx 4// unsigned __int32 0 ~ 4,294,967,295 5 6#define MSB (~( -1U >> 1 )) 7 8// See http://www.nminoru.jp/~nminoru/programming/bitcount.html 9// ビットを数える・探すアルゴリズム 10int count_bits(unsigned bits) { 11 int num = 0; 12 13 for ( ; bits != 0 ; bits &= bits - 1 ) { 14 num++; 15 } 16 17 return num; 18} 19 20int count_bitsx(int bits) { 21 int num; 22 23 num = (bits >> 1) & 03333333333; 24 num = bits - num - ((num >> 1) & 03333333333); 25 num = ((num + (num >> 3)) & 0707070707) % 077; 26 27 return num; 28} 29 30void print_bits(unsigned val) { 31 for (unsigned mask = MSB; mask; mask >>= 1) { 32 if (val & mask) { 33 putchar('1'); 34 } else { 35 putchar('0'); 36 } 37 } 38} 39 40int main(void) { 41 unsigned nx; 42 43 printf("type non negative (0..4294967295) "); 44 scanf("%u",&nx); 45 46 print_bits(nx); 47 putchar('\n'); 48 printf("0x%x\n", nx); 49 printf("count bit: %d\n", count_bits(nx)); 50 printf("count bit: %d\n", count_bitsx(nx)); 51 52 return 0; 53}
実行例
$ gcc bit.c $ ./a.out type non negative (0..4294967295) 7 00000000000000000000000000000111 0x7 count bit: 3 count bit: 3 $ ./a.out type non negative (0..4294967295) 4294967295 11111111111111111111111111111111 0xffffffff count bit: 32 count bit: 30
参考サイト http://www.nminoru.jp/~nminoru/programming/bitcount.html にあった count_bitsx() は int では動作しますが、unsinged では動作しません。
4294967295 のビット数が 30 となってしまいました。
32 が返ってkるように修正する方法がわかる方は投稿をしていただれば幸いです。
投稿2015/08/29 00:12
総合スコア22324
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2015/08/30 15:41
0
#include <stdio.h>
#define MSB ~( -1U >> 1 )
int main(void)
{
unsigned int bit;
unsigned int value;
printf("unsigned int = "); scanf("%u",&value); printf("Binary notation = "); for ( bit=MSB; bit != 0; bit >>= 1 ) { if ( value & bit ) { putchar('1'); } else{ putchar('0'); } } putchar('\n'); return 0;
}
処理説明
1.標準入出力ライブラリをインクルード
2.unsigned intの最上位ビットを定義
3.メイン関数定義
4.変数を定義
5.「unsigned int = 」を表示
6.unsigned int型で入力
7.「Binary notation = 」を表示
8.for文でMSBをbitに入れ、右シフトし、0になるまで以下の2つの処理を繰り返す。
8.1.該当ビットがONだったら、1を出力
8.2.該当ビットがOFFだったら、0を出力
9.改行を出力
10.終了
※ なるべく、コードを省略しない方が読みやすくなります。
※ ビットカウントのアルゴリズムは、下記も参考にして下さい。追記:2015.08.29 20:54
bits = bits - ((bits >> 1) & 033333333333) - ((bits >> 2) & 011111111111);
bits = ((bits + (bits >> 3)) & 030707070707) % 077;
投稿2015/08/28 21:34
編集2015/08/29 11:57総合スコア55
0
こういうことでしょうか。
上手い指摘を思いつかなくて、実装をそのまま書いてます…ごめんなさい。
C
1#define MSB_ON ~( -1U >> 1 ) 2void print_bits(unsigned x) 3{ 4 int i; 5 for(i=int_bits()-1;i>=0;i--){ 6 putchar((x&MSB_ON)?'1':'0'); 7 x<<=1; 8 } 9}
元の処理だと、以下の問題があります。
・xの内容が更新されない
・1ビットシフト後に最下位ビットの評価を行うので入力値の最下位ビットが評価前に捨てられる
また最後に表示するビットの並びが逆転しているので、上記のコードは最上位ビットを評価するようにしています。
投稿2015/08/28 17:12
編集2015/08/28 17:17退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2015/08/29 15:30 編集
2015/08/30 06:43
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/08/30 06:45