10進数では有限なのに、2進数では無限になる理由

広告

基本情報技術者試験やプログラミングを学び始めると、

なぜ 0.1 や 0.2 はコンピュータで誤差が出るの?

という疑問を持つ人が多くいます。

その理由は、「2進数では有限で表せない数があるから」です。

今回は、その仕組みを分かりやすく見ていきましょう。


小数を2進数へ変換する方法

2進数の小数は、

2倍して、整数部分を取り出す

という操作を繰り返して求めます。

例えば 1/3 を変換すると、

1/3 × 2 = 2/3 → 0
2/3 × 2 = 4/3 → 1(残り1/3)

残りがまた 1/3 に戻りました。

つまり、この先も同じことの繰り返しになります。

1/3 = 0.010101010101...₂

1/5 を変換すると?

同じように計算します。

1/5 × 2 = 2/5 → 0
2/5 × 2 = 4/5 → 0
4/5 × 2 = 8/5 → 1(残り3/5)
3/5 × 2 = 6/5 → 1(残り1/5)

ここで最初の 1/5 に戻ります。

つまり、

1/5 = 0.001100110011...₂

となります。


2/5 や 3/5 は?

同じように循環します。

1/5 = 0.001100110011...₂
2/5 = 0.011001100110...₂
3/5 = 0.100110011001...₂
4/5 = 0.110011001100...₂

どれも有限にはなりません。


有限になるかどうかの判断方法

実は簡単なルールがあります。

まず分数を約分します。

そして、

約分後の分母が 2 のべき乗(2、4、8、16…)だけなら、2進数では有限になります。

例えば、

分数分母2進数
1/22有限
1/44有限
1/88有限
1/1616有限

一方、

分数分母2進数
1/33無限
1/55無限
1/66無限
3/1010 = 2×5無限

となります。

ポイントは、

分母に「2以外の素因数」が残ると、2進数では循環小数になる

ということです。


10進数では有限なのに、2進数では無限になることがある

例えば、

1/10 = 0.1

これは10進数では有限です。

しかし2進数では、

0.00011001100110011...₂

となり、無限に続きます。

逆に、

1/2
1/4
1/8

などは10進数でも2進数でも有限になります。


10進数で無限なら、2進数でも無限?

答えは はい です。

例えば、

1/3

は、

0.333333...₁₀

ですが、

0.01010101...₂

となり、2進数でも循環します。

理由は、10進数で有限になるためには、

分母が

2 と 5

だけで構成されている必要があります。

10進数で無限ということは、

3
7
11

などの素因数が残っています。

2進数では「2」しか使えないため、それらを表すことはできません。

その結果、2進数でも必ず循環小数になります。


これが double の誤差につながる

C# の double は、

値を 2進数 で保存しています。

例えば、

double x = 0.1;

と書いても、

実際には

0.000110011001100110011...

という無限に続く2進数になります。

しかし、コンピュータは有限のビット数しか保存できません。

そのため途中で丸められ、

0.10000000000000001...

のような誤差が発生します。

これが、

0.1 + 0.2 != 0.3

になる理由です。


まとめ

  • 小数を2進数へ変換するときは、「2倍して整数部分を取り出す」を繰り返す。
  • 約分後の分母が 2のべき乗 なら、2進数で有限になる。
  • 分母に 2以外の素因数 が残ると、2進数では循環小数になる。
  • 1/52/53/54/5 はすべて2進数では無限に続く。
  • 10進数で有限でも、2進数では無限になることがある(例:0.1、0.2)。
  • double は2進数で値を保存するため、丸め誤差が発生することがある。

この仕組みを理解すると、「なぜコンピュータでは小数の誤差が起きるのか」が納得できるようになります。

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

広告