@wgatwt00a (Rituryo kokka)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

C言語 小数点付き2進数→10進数に変換する方法

Q&A

Closed

解決したいこと

お世話になります。
問題の内容は、”2 進表現の小数を 10 進表現の小数に変換する課題である.通常はこのように 2 進表現の小数が文字列で与えられることはない.2 進小数の理解を深めるための課題である.0 以上 1 未満の実数が 2 進表現でコマンドライン引数に与えられる.この実数を 10 進表現で小数第 6 位まで出力せよ.”です。
自分でプログラムを作成しましたがテストが途中で失敗し、考えてもわからないため皆様にお聞きしたいです。

発生している問題・エラー

==== テスト 7 (Test case 7) ====
$ ./binary2double 0.11110000
0.933594==== 期待される出力 (Correct output) ====
0.937500
==== 出力の違い (Different lines) ====
--- 7.correct   2023-02-01 09:00:05.819287500 +0900
+++ 7.out       2023-02-01 14:51:52.510809600 +0900
@@ -1 +1 @@
-0.937500
+0.933594
\ No newline at end of file
================
テスト 7 失敗(failed)

該当するソースコード

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
   double d, sum, x;
   d = atof(argv[1]);
   for (int i = 0; i < 8;i++){
     x = 1;
     d = d * 10;
     if (d >= 1) {
       for(int l = 0; l < i + 1 ;l++){
         x *= 0.5;
       }
       sum += x;
       d = d - 1;
     }
   } 
   printf("%.6f",sum);
   return 0;
}
0 likes

4Answer

たとえば十進数の 0.1 という値を二進数で表現しようとしたとき、 0.0001100110011001100110011001100110011001100110011001101 というように同じパターンが無限に繰り返される循環小数となります。 十進数ではキリのよい値に見えても二進数の世界ではそうではありません。 double 型では正確に保持することが不可能なので double 型で格納しようとした段階で既に誤差が生まれています。

質問の事例では、数式上なら 1 ピッタリになるはずのときに実際には誤差で 0.999999999999988 となっているので d >= 1 が偽となり想定通り動いていませんでした。

小数点数を等号で比較するのはほぼ常に誤りだと言っても過言ではありません。 私も文字として処理するのが妥当だと思いますが、どうしても double の計算としてやりたいということであればあり得る誤差の幅の分だけ余裕をもって判定するという方法をとれなくはないです。 しかしどれだけの誤差があり得るのか、余裕をどう設定すればよいのか見積もる能力がない内にその方法をとるべきではないと私は考えます。

1Like

Comments

  1. @wgatwt00a

    Questioner

    なぜ失敗したのか初心者の私にもわかりやすく説明していただきありがとうございます。おかげで理解でき、すっきりしました!
    Vercleneさんにも言われたように他の方法で作成することにします。
    ありがとうございましたm(__)m
編集済 @imagou

0.933594と出力されるので

どうみても0.9375がexpectedなのに変な回答つけないでください.
手計算で簡単に検証できますので.

-7.correct   2023-02-01 09:00:05.819287500 +0900
+7.out       2023-02-01 14:51:52.510809600 +0900
@@ -1 +1 @@
-0.937500
+0.933594
1Like

とりあえずatof関数は10進表現を入力にとるので,2進表現の入力に使っても意味がありません.
題意からして1文字ずつ自前でパースするのが良さそうですので,書き直しをオススメします.

それとC#はCとは全く異なる言語ですので,適切なタグを設定してください.

0Like

Comments

  1. @wgatwt00a

    Questioner

    そうなのですか。。できればこの方法でやりたいのでもう少し考えてみて無理そうなら他の方法でやってみようと思います。
    タグ直しました。ありがとうございますm(__)m
  2. そもそもatofを使うのが間違いと指摘しているのにこの方法でというのはどうにも.

@Verclene すみません、大きく勘違いしていたようです。失礼いたしました。
私の回答は削除いたしました。

0Like

Your answer might help someone💌