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.3 を fabs(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.1 を fabs(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.1 を fabs(c - 0.1) < 1e-9 にします。
よくある誤解
型をfloatからdoubleに変えても解決しません。精度が上がるだけで、2進数で0.1を正確に表現できないという根本的な制約は変わらないためです。小数の比較は、差の絶対値が十分小さいかどうか(許容誤差)で判定します。
まとめ
0.1 + 0.2 == 0.3 が偽になる理由は上級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。