※スマホ対応はしてません。

タグ: Number

0.1+0.2は0.3になりません(JavaScript おれおれ Advent Calendar 2011 – 13日目)

カテゴリー: JavaScript, Web

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

JavaScriptで123.toString()はエラーになるけど、123..toString()は正常に動作する。これってトリビアの種になりませんか? (JavaScript おれおれ Advent Calendar 2011 – 12日目)

カテゴリー: JavaScript, Web

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

というわけで、123.toString()は駄目だけど、ドット.を二つにした123..toString()はvalidです。

なんでかっていうと、123.までが数値として解釈されるから、です。

ですから123.toString()というコードは、123.という数値の直後にメソッド名toStringが出現する、と解釈されるため、パースエラーになっちゃいます。次のコードと等価です。

(123.)toString()

ドット.を二つにすると123.という数値の次にはドット演算子.があって、それからメソッド名が出現すると解釈されますので、123.に対してNumber.prototypeのtoString()が呼び出される事になります。

(123.).toString()

このあたり、JavaScript: The Good Partsの「2.3 数値」の図がわかりやすいです。