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

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

ただいまの
回答率

90.62%

  • C

    3561questions

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

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

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,198

reotantan

score 245

すいません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;
}

コード
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+1

【普通の解説】
※ 宗教的な理由で、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が表示されることがわかると思います。


【おまけ】汎用性を持たせてみました。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>

#define UINTMAX_BITS_SIZE (sizeof(uintmax_t) * CHAR_BIT)
#define print_bits(x) print_bits_n((x), sizeof(x) * CHAR_BIT)

int count_bits(uintmax_t bits);
void print_bits_n(uintmax_t bits, int width);

int main(void)
{
        unsigned int nx;
        printf("type positive number (%u..%u): ", 0, UINT_MAX);
        if (scanf("%u",&nx) != 1) {
                printf("not number");
                exit(1);
        }

        print_bits(nx);
        putchar('\n');
        printf("%d\n", count_bits(nx));

        return 0;
}

int count_bits(uintmax_t bits)
{
        for (int i = 1; i < UINTMAX_BITS_SIZE; i <<= 1) {
                uintmax_t mask = (UINTMAX_C(1) << i) - 1;
                for (int j = (i << 1); j < UINTMAX_BITS_SIZE; j <<= 1) {
                        mask += mask << j;
                }
                bits = (bits & mask) + (bits >> i & mask);
        }
        return (int)bits;
}

void print_bits_n(uintmax_t bits, int width)
{
        for (int i = width - 1; i >= 0; i--) {
                putchar(bits & (UINTMAX_C(1) << i) ? '1' : '0');
        }
}
特徴は下記の通りです。

  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/30 15:45

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

    キャンセル

0

こういうことでしょうか。
上手い指摘を思いつかなくて、実装をそのまま書いてます…ごめんなさい。
#define MSB_ON ~( -1U >> 1 )
void print_bits(unsigned x)
{
    int i;
    for(i=int_bits()-1;i>=0;i--){
        putchar((x&MSB_ON)?'1':'0');
        x<<=1;
    }
}
元の処理だと、以下の問題があります。
・xの内容が更新されない
・1ビットシフト後に最下位ビットの評価を行うので入力値の最下位ビットが評価前に捨てられる

また最後に表示するビットの並びが逆転しているので、上記のコードは最上位ビットを評価するようにしています。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/08/30 00:27 編集

    動作の流れを追いたいという話でしたら、むしろデバッガの使い方を覚えて、ステップ実行してみることをお勧めします。
    たぶん人に聞くよりもその方が具体的に分かる事も多いと思います。

    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回ビットの評価をしています。

    キャンセル

  • 2015/08/30 15:43

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

    キャンセル

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/30 15:44

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

    キャンセル

0

#include  <stdio.h>

// https://msdn.microsoft.com/ja-jp/library/s3f49ktz.aspx
//   unsigned __int32  0 ~ 4,294,967,295

#define MSB (~( -1U >> 1 ))

// See http://www.nminoru.jp/~nminoru/programming/bitcount.html
//  ビットを数える・探すアルゴリズム
int count_bits(unsigned bits) {
  int num  = 0;

  for ( ; bits != 0 ; bits &= bits - 1 ) {
    num++;
  }

  return num;
}

int count_bitsx(int bits) {
  int num;

  num = (bits >> 1) & 03333333333;
  num = bits - num - ((num >> 1) & 03333333333);
  num = ((num + (num >> 3)) & 0707070707) % 077;

  return num;
}

void print_bits(unsigned val) {
  for (unsigned mask = MSB; mask; mask >>= 1) {
    if (val & mask) {
      putchar('1');
    } else {
      putchar('0');
    }
  }
}

int main(void) {
  unsigned nx;

  printf("type non negative (0..4294967295) ");
  scanf("%u",&nx);

  print_bits(nx);
  putchar('\n');
  printf("0x%x\n", nx);
  printf("count bit: %d\n", count_bits(nx));
  printf("count bit: %d\n", count_bitsx(nx));

  return 0;
}
実行例
$ 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/30 15:44

    ありがとうございます、とても参考になりました!

    キャンセル

  • 2015/08/31 00: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);
    }

    キャンセル

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

  • ただいまの回答率 90.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    while文のなかにif文

    その名の通りwhile文のなかにif文が入っているコードがあったのですが なんだか違和感を感じました。while文の中にif文をいれることってけっこうありますか? 詳しいかた教えて

  • 解決済

    ifの適用範囲

    ifの波括弧はputcharも含んでいると思うのですが、なぜpucharはifに縛られないのでしょうか? ’#include<stdio.h>  int main(void){

  • 受付中

    点数別分布グラフ

    点数分布のグラフですが、少し長いように感じました。もう少し短くすることはできますか? またこのコードに対して何かご意見がありましたらお願いします。 #inc

  • 解決済

    複数の変数にループで一気に値を代入する方法はありますか?(配列を用いないとしたら)

    たとえば     int a,b,c,d,e,f,g,h,i,j,k,l;     a = 2;     b = a + 2;     c = b + 2;     d = c +

  • 解決済

    javaのカウントアップについて

    javaのEclipseを使っています。 カウントアップ後、表示する度に、 1, 2, 3, …と表示するプログラムを作りたいです。 プログラム例を教えて下さい。 2つのインス

  • 受付中

    C言語 ビット単位の論理演算

    このコードの内容が全くもって理解できません。 どなたか一から説明してくだされば幸いです。 include<stdio.h>はこの質問のテンプレートではおかしくなるので省略し

  • 解決済

    c言語 ファイル出力

    putchar() や fputc() といった関数は 非負整数1バイトを出力するわけですが、なぜ引数が int なのでしょうか。

  • 解決済

    pythonのテキスト処理について

    バイナリ文字の処理なのですがうまく変換できずに混乱してしまったので,質問致します. python2.7でバイナリ文字の処理をしています. 2の補数,4バイト固定小数点です.

同じタグがついた質問を見る

  • C

    3561questions

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