JavaScript おれおれ Advent Calendar 2011 – 13日目

JavaScriptに限った話じゃないんですけどね。

console.log(0.1 + 0.2 == 0.3);  // => false

なんでかというと、現代のコンピューターの性質で、数値を2進数、つまり2の階乗の和で表現しようとするためです。

例えば0.5は簡単ですね。2-1です。また0.25は2-2ですから、0.75は2-1+2-2という事になります。

ちなみにJavaScriptで階乗を扱う場合はMath.pow()です。

console.log(Math.pow(2, -1));  // => 0.5
console.log(Math.pow(2, -2));  // => 0.25
console.log(Math.pow(2, -1) + Math.pow(2, -2));  // => 0.75

それでは0.1はどう表せば良いでしょうか?

console.log(0.1.toString(2));  // => "0.0001100110011001100110011001100110011001100110011001101"

おわかり頂けるでしょうか、これ、循環小数になります。10進数でいうところの1/3 = 0.33333333…みたいなやつです。

ですので、0.1は2進数の世界に生きるコンピューターでは正確に扱う事ができません。なので近似値で扱うのですが、実際の数値とはちょっとだけずれているので、計算を行うと変な結果になってしまったりするわけです。

こんなコードは危険です。

for (var i = 0.1; i < 1; i += 0.1) {
  console.log(i);
}
0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999

ループカウンター実数ではなく整数を使うようにしましょう。

for (var i = 1; i < 10; i += 1) {
  console.log(i / 10);
}
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9