Code Fix

上級

0.1 + 0.2 == 0.3 が偽になる理由

doubleやfloatは2進数で値を表現するため、0.1や0.2のような小数を正確には表現できません。==でぴったり比較すると、ほぼ確実に一致しません。

なぜエラーが出ないのか

出力: not equal
(エラーなし)
Cは何も報告しません。コンパイルも実行も正常に完了するためです
出力: not equal
実際の挙動 — 期待した結果と食い違っている箇所
見つけ方
エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます

このエラーが出る典型パターン

パターン1

 1  #include <stdio.h>
 2  #include <math.h>
 3  
 4  int main(void) {
 5      double a = 0.1 + 0.2;
 6      if (a == 0.3            ) {
                      ^
 7          printf("equal\n");
 8      } else {
 9          printf("not equal\n");
10      }
11      return 0;
12  }
出力: not equal期待: equal

0.1と0.2は2進数で正確に表現できないため、0.1 + 0.2はぴったり0.3にはなりません。==での比較はほぼ確実に失敗します。差の絶対値が十分小さいかどうか(許容誤差)で判定します。

直し方: a == 0.3fabs(a - 0.3) < 1e-9 にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  #include <stdio.h>
 2  #include <math.h>
 3  
 4  int main(void) {
 5      double b = 1.1 - 1.0;
 6      if (b == 0.1            ) {
                      ^
 7          printf("equal\n");
 8      } else {
 9          printf("not equal\n");
10      }
11      return 0;
12  }
出力: not equal期待: equal

引き算の結果も同じ問題を抱えます。1.1 - 1.0は数学的には0.1ですが、浮動小数点の内部表現では誤差を含みます。

直し方: b == 0.1fabs(b - 0.1) < 1e-9 にします。

この問題を解いてみる →

パターン3

 1  #include <stdio.h>
 2  #include <math.h>
 3  
 4  int main(void) {
 5      double c = 0.3 - 0.2;
 6      if (c == 0.1            ) {
                      ^
 7          printf("equal\n");
 8      } else {
 9          printf("not equal\n");
10      }
11      return 0;
12  }
出力: not equal期待: equal

型をfloatからdoubleに変えても解決しません。2進数で0.1を正確に表現できないという根本的な制約は変わらないためです。

直し方: c == 0.1fabs(c - 0.1) < 1e-9 にします。

この問題を解いてみる →

よくある誤解

型をfloatからdoubleに変えても解決しません。精度が上がるだけで、2進数で0.1を正確に表現できないという根本的な制約は変わらないためです。小数の比較は、差の絶対値が十分小さいかどうか(許容誤差)で判定します。

まとめ

0.1 + 0.2 == 0.3 が偽になる理由は上級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)