たった4ビットで分かる!0.1が保存できない理由
「0.1 + 0.2 が 0.3 にならないことがある」
この現象を見て、
「コンピュータって計算を間違えているの?」
と思ったことはありませんか?
実は、計算が間違っているのではありません。
値を保存するときに、すでに丸められていることが原因です。
今回は、本物の double よりもずっと小さい、
整数部1ビット・小数部3ビット
しか保存できない世界で考えてみましょう。

この世界で保存できる数

小数部が3ビットしかないため、保存できる値は次の8種類だけです。
| 2進数 | 10進数 |
|---|---|
| 0.000 | 0.000 |
| 0.001 | 0.125 |
| 0.010 | 0.250 |
| 0.011 | 0.375 |
| 0.100 | 0.500 |
| 0.101 | 0.625 |
| 0.110 | 0.750 |
| 0.111 | 0.875 |
この表を見ると、
0.100(10進数)
という値は存在しないことが分かります。
つまり、この型では 0.1をそのまま保存することはできません。
0.1を2進数に変換すると?
10進数の
0.1
を2進数へ変換すると、
0.000110011001100110011…
となります。
途中で終わらず、ずっと続く数です。
保存できるのは3ビットだけ

ところが、この型では
0.xxx
までしか保存できません。
そのため、
0.000110011…
を途中で丸める必要があります。
近い値を探すと、
| 保存候補 | 10進数 |
| 0.000 | 0.000 |
| 0.001 | 0.125 |
となります。
10進数の0.1は、
- 0.000との差:0.100
- 0.125との差:0.025
となるため、
0.125の方が近いことが分かります。
その結果、
0.100
↓
0.001₂
↓
0.125
として保存されます。
つまり、
保存したつもりは
0.100
ですが、
実際に保存されているのは
0.125
なのです。
この状態で計算すると?

例えば、
0.1 + 0.1
を計算したいとします。
しかし、コンピュータの中では
0.125 + 0.125
になっています。
その結果は、
0.250
です。
本来期待していた
0.200
とは違う結果になります。
つまり、
計算が間違ったのではなく、保存された値が最初から違っていた
ということです。
実際のdoubleも同じ
ここまでの例は、
理解しやすいように
小数部3ビット
という極端な例で説明しました。
実際のC#の double は約53ビットの精度があります。
そのため誤差は非常に小さくなりますが、
仕組みは全く同じです。
0.1
↓
2進数へ変換
↓
無限に続く
↓
保存できるビット数まで丸める
↓
近似値として保存
つまり、
ビット数が違うだけで、本質は同じなのです。
だから実際には、
Console.WriteLine(0.1 + 0.2);
を実行すると、
0.30000000000000004
のような結果になることがあります。
これは計算ミスではなく、
保存された値が近似値だからです。
decimalではどうなる?
C#には decimal 型があります。
decimal は10進数を基準として値を保持するため、
decimal a = 0.1m;
decimal b = 0.2m;
Console.WriteLine(a + b);
とすると、
0.3
と表示されます。
そのため、
- 金額
- 消費税
- ポイント計算
- ファンクションポイント法
など、
10進数で正確さが求められる計算では decimal がよく使われます。
まとめ
今回のポイントは次の4つです。
- コンピュータは小数を2進数で保存する。
- 0.1は2進数では無限に続く数になる。
- 保存できるビット数まで丸められるため、最初から近似値になる。
doubleも同じ仕組みで、違うのは使えるビット数が多いだけである。
「コンピュータは計算を間違える」のではなく、
保存できる形に丸めてから計算している。
これが、丸め誤差の正体なのです。
イラストの差し込み位置
- アイキャッチ(記事の一番上)
- 「4ビットしかない世界で、0.1が入りきらずに丸められる」イメージ
- 「この世界で保存できる数」の直後
- 8段の階段状に「0.000 → 0.001 → … → 0.111」と並び、0.1がその間にあることを示す図
- 「保存できるのは3ビットだけ」の直後
- 「0.1 → 2進数 → 無限に続く → 0.125へ丸められる」のフローチャート
- 「この状態で計算すると?」の直後
- 「0.1(保存時に0.125)+0.1(保存時に0.125)=0.25」の流れを矢印で表した図
この構成なら、生徒さんは「誤差は計算時ではなく保存時に発生する」という本質を直感的に理解しやすくなります。









ディスカッション
コメント一覧
まだ、コメントがありません