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

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

ただいまの
回答率

88.93%

IEEE規格754による実数表現について

解決済

回答 3

投稿 編集

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

nayuta314

score 12

質問内容

長さが32の0と1の列を入力して、このビット列の表す実数値を出力するC言語のプログラムで実数表現の仕方はIEEE規格754に従うものと仮定するCプログラムを作成したいのですが、
コンパイルして動作確認したところ正しい値が出てこないです。
どこが間違えているのかわからないです。

IEEE規格754による実数表現を行います。
長さが32の1と0の列を入力してください。:01000001011100000000000000000000

====入力ビット列は次のように解釈できます。
整数として00の値を持ち、 
小数点以下0.000000の値を持ちます。

該当のソースコード

#include<stdio.h>
#include<stdlib.h>
int main(void){
  int bit[32],i,c;
  double syosuu;
  unsigned char unsigned_val;
  signed char signed_val;

  printf("IEEE規格754による実数表現を行います。\n"
     "長さが32の1と0の列を入力してください。:");
  for(i=31;i>=0; ){
    switch(c=getchar()){
      case '0': case '1':
      bit[i--] = c-'0';
      break;
      case ' ': case '\n': case '\t':
      break;
      default:
      printf("無効な文字です.\n");
      exit(EXIT_FAILURE);
    }
  }

  unsigned_val = bit[31];
  signed_val = -bit[31];
  for(i=9;i>=0;i--){
    unsigned_val = unsigned_val*2+bit[i];
    signed_val = signed_val*2+bit[i];
  }
  syosuu=bit[31];
  for(i=10;i>=31;i++){
    syosuu=(syosuu/2)+bit[i];
    }
  printf("\n====入力ビット列は次のように解釈できます。\n"
  "整数として%d%dの値を持ち、 \n"
  "小数点以下%fの値を持ちます。\n",
     signed_val,unsigned_val,syosuu);
  return 0;
}

発生している問題・エラーメッセージ

IEEE規格754による実数表現を行います。
長さが32の1と0の列を入力してください。:01000001011100000000000000000000

====入力ビット列は次のように解釈できます。
整数として00の値を持ち、 
小数点以下0.000000の値を持ちます。

※整数15小数点以下0.000000と出力される予定です

追記

皆さんの意見を参考にソースコードを組み替えてみました。
ご指導のほどよろしくお願いします。

#include<stdio.h>
#include<stdlib.h>
int main(void){
  int bit[32],i,c;

  printf("IEEE規格754による実数表現を行います。\n"
     "長さが32の1と0の列を入力してください。:");
  for(i=31;i>=0; ){
    switch(c=getchar()){
    case '0': case '1':
      bit[i--] = c-'0';
      break;
    case ' ': case '\n': case '\t':
      break;
    default:
      printf("無効な文字です.\n");
      exit(EXIT_FAILURE);
    }
    signed char E;
    int M;
    int x,i;
    char NaN,Inf;
    E = -bit[31];
    for(i=9;i>=0;i--){
      E = E*2+bit[i];
    }
    M=bit[32];
    for(i=10;i>=31;i++){
      M=M/2+bit[i];
    }
    if(E==128&&M==0){
      printf("Inf");
    }else if(-127<E && E<128){
      x=(-1)^bit[0]*(1+M)*(2^E);
      printf("%f",x);
    }else if(M!=0&&E==128){
      printf("NaN");
    }else{
      x=(-1)^bit[0]*M*2^(E+1);
      printf("x");
    }
  }
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

+3

int型が32bit、float型がIEEE754のfloatであるようなC言語処理系を使う前提で、とりあえず動くであろうコード例は割合簡単(というより身も蓋もないコード)なのですが・・・

int bits = 0;
for (int i = 0; i < 32; i++) {
  bits = (bits << 1) | bit[i];
}
// この時点で32bitのビットパターンが左の桁をMSBに、右の桁がLSBとなるようにbitsに格納されている
float fval = *(float&)&bits;
printf("%f\n", fval);

自分が問題として出題する立場なら、上記のようなコードではなく、指数部、仮数部の範囲をしかるべく意識してそれをfloatへ変換するようなコードを求めるかも知れません。そのような回答を得るにはまずIEEE754の形式を理解する必要がありますが、この場では少々回答が長くなりますのでwikipediaのページなどを調べて形式について学んでみてください。


なお、変数unsigned_val、signed_valはchar型の幅(8bit)しかないので、32ビット分を詰め込もうとしても詰め込めません。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

checkベストアンサー

+1

IEEE単精度ですから、まず用語としては
符号(bit31)
指数部(bit30~bit23)
仮数部(bit22~bit0)
となります。
それぞれを分解したうえで、指数部については-127(本来の値に対して127の下駄をはかせているため)し、
仮数部には 1 を足さねばなりません(常に1.????? になるように正規化することで精度を1ビット多くしている)

それを踏まえますと、いろいろコードと結果の解釈が誤っていることがわかります。

計算する部分だけ書き換えるとこうなります。

    double kasuu, keta;
    int sisuu;
    int sign;

    sign = -bit[31];
    sisuu = 0;
    for (i = 30; i >= 23; i--) {
        sisuu = sisuu * 2 + bit[i];
    }
    sisuu -= 127;
    keta = 1;
    kasuu = 1;
    for (i = 22; i >= 0; i--) {
        keta /= 2;
        kasuu += keta * bit[i];
    }


これで符号=0(正)、指数部=3(130 = 3 + 127)、仮数部 1.875 を得られますね。
(1.875 * (2^3) = 1.875 * 8 = 15)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

外部サイトへ丸投げで申し訳ないのですが、「浮動小数点、その中身とは」 がとても参考になりそうに思いました。(waybackmachineがあってよかった)

学習が目的ならこの記事にようにパディングを含まないようにしたunionを使うと便利です。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/05/01 17:20

    このサイトはCのコードも色々な値の具体例ものってて分かりやすいですね!

    キャンセル

  • 2017/05/01 18:33

    ですよね。コンパクトなのに、知識だけでもなく実装だけでもなくで、とても良いと思ったので紹介したくなりました。(サイトごと無くなってたので探すのに時間かかった…)

    キャンセル

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

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

関連した質問

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