質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

4970閲覧

ビット構成を表示するプログラム

reotantan

総合スコア295

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2015/08/28 16:33

編集2015/08/29 13:36

すいません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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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が何をしているかというと、xi分だけシフトするという意味です。たとえば、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}

特徴は下記の通りです。

  1. 参考サイトのバージョン5を汎用化。いくらでも大きく、かつ、unsignedで処理が可能に。(ただ、高速を目指すなら、mask値はテーブル化やメモ化すべきだろうが、面倒だったのでそこまではしてない)
  2. unsigned intの大きさが16bitsでも、32bitsでも、64bitsでも、128bitsでも、256bitsでもいくらでも大きくてもたぶん大丈夫。
  3. 表示は普通に上からビット演算することで、単純化。ただし、速くなるかどうかはわからない。 (あらかじめテーブル作ったら速くなりそう)
  4. 符号有り整数で負の値を渡すと、カウントはうまくいかないので、unsignedでキャストしてから、渡してね。unsignedなら正しく暗黙的キャストするので何でもOK。
  5. C99にちゃんと対応していないコンパイラでは通らない。(GCCとClangで確認済み、Visual Studioは未確認)

> katoyさん
参考サイトのバージョン4をunsignedにしたり、汎用化するのは私には無理でした。ごめんなさい。代わりにバージョン5で対応したので、許してください。

投稿2015/08/29 23:38

編集2015/08/30 00:22
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

reotantan

2015/08/30 06:45

ありがとうございました、とても助かります
guest

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

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

reotantan

2015/08/30 06:44

ありがとうございます、とても参考になりました!
退会済みユーザー

退会済みユーザー

2015/08/30 15:41

どうもcount_bitsx関数の計算方法だと、最上位2ビットを処理できないようですね。 似たような計算式に MIT HACKMEM というものがあるようですよ。 int bitcount (unsigned long long n) { unsigned long long tmp; tmp = n - ((n >> 1) & 0333333333333333333333ull) - ((n >> 2) & 0111111111111111111111ull); tmp += tmp >> 3; return (tmp & 0707070707070707070700ull) % 63 + (tmp & 7); }
guest

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
t2oando

総合スコア55

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

reotantan

2015/08/30 06:44

丁寧な説明ありがとうございます。
guest

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 編集

動作の流れを追いたいという話でしたら、むしろデバッガの使い方を覚えて、ステップ実行してみることをお勧めします。 たぶん人に聞くよりもその方が具体的に分かる事も多いと思います。 Windowsの場合はVisualStudio、Macの場合はXCodeを用いればデバッグは非常に楽にできるので、デバッガの使い方を調べてみてはどうでしょう。 >VisualStudioでの例 http://visualstudiostudy.blog.fc2.com/blog-entry-8.html ちなみに、1 -> i に更新されたprint_bits関数のfor文は(最上位ビットから順に)最下位ビットに評価したいビットの値をシフトしています。 32bit幅だったら、x>>31, x>>30, x>>29 ... x>>2, x>>1, x>>0というように1ビットずつ。合計32回ビットの評価をしています。
reotantan

2015/08/30 06:43

なるほど、理解が進みました。 ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問