二進数の計算で「10進数の 0.1」を扱うと丸め誤差が出る理由

(情報処理試験・プログラミング初学者~中級者を想定しています)


プログラミングを学び始めた人が、ほぼ必ず一度は出会う疑問があります。

「0.1 + 0.2 が 0.3 にならないのはなぜ?」

これは言語のバグでも、計算ミスでもありません

原因は、二進数では 10進数の 0.1 を正確に表現できないことにあります。

本記事では、

  • なぜ 0.1 が正確に表せないのか
  • 二進数での具体的な変換過程
  • 丸め誤差が発生する仕組み
  • 実務や試験での正しい理解ポイント

を順序立てて解説します。


結論から言うと

10進数の 0.1 は、二進数では無限小数になるため、必ず誤差が生じます。

これは仕様上の問題であり、

どの言語(C / C# / Java / Python / JavaScript)でも同じです。


10進数の 0.1 を二進数に変換してみる

小数の基数変換の基本

小数を二進数に変換するときは、

「2 を掛けて整数部分を取り出す」操作を繰り返します。


0.1 × 2 を繰り返す

回数計算整数部
10.1 × 2 = 0.20
20.2 × 2 = 0.40
30.4 × 2 = 0.80
40.8 × 2 = 1.61
50.6 × 2 = 1.21
60.2 × 2 = 0.40
70.4 × 2 = 0.80
80.8 × 2 = 1.61

ここで注目してください。

0.2 → 0.4 → 0.8 → 1.6 → 0.6 → 0.2

という循環が発生しています。


二進数表現(無限小数)

整数部を並べると、

0.000110011001100110011...

つまり、

0.1(10進) = 0.0001100110011…(2進)

終わりません。


なぜ無限小数になるのか?

10進では「割り切れる」が、2進では割り切れない

  • 10進数の 0.1 = 1 ÷ 10
  • 10 = 2 × 5

👉 5 という因数が含まれるため、2進では割り切れない

これは数学的に避けられません。

分数10進2進
1/20.50.1
1/40.250.01
1/80.1250.001
1/100.1無限小数

コンピュータはどう処理しているか

浮動小数点数(IEEE 754)

多くの言語では IEEE 754 という規格で数値を扱います。

  • 小数は 有限ビット数 しか持てない
  • 無限小数は 途中で切り捨て or 丸め るしかない

結果として、

0.1 ≒ 0.10000000000000000555...

のような 近似値 が内部的に保存されます。


実際のコード例

C# の例

double a = 0.1;
double b = 0.2;
Console.WriteLine(a + b);

出力結果:

0.30000000000000004

これは誤差が「見えている」だけです。


よくある誤解

「計算精度が低いから?」

❌ 違います

👉 どれだけ精度を上げても、無限小数は完全には表せません


「0.1 が特別おかしい?」

❌ 違います

👉 10進で有限でも、2進では無限になる数は多数あります


実務・試験での正しい扱い方

1. 浮動小数点数の比較は直接しない

if (a == 0.3)  // NG

代わりに:

if (Math.Abs(a - 0.3) < 1e-9) // OK

2. 金額計算は decimal を使う(C#)

decimal x = 0.1m;
decimal y = 0.2m;
Console.WriteLine(x + y); // 0.3

※ decimal は 10進数ベース で設計されています。


3. 情報処理試験でのポイント

  • 0.1 は二進数で正確に表せない
  • 浮動小数点は近似値
  • 丸め誤差は仕様

この3点を理解していれば、

計算問題・概念問題ともに対応できます。


まとめ

  • 10進数の 0.1 は、二進数では無限小数になる
  • コンピュータは有限ビットで近似するため誤差が出る
  • これはバグではなく「設計上の必然」
  • 試験・実務では「誤差が出る前提」で扱うことが重要

訪問数 2 回, 今日の訪問数 2回