web-dev-qa-db-ja.com

Javascriptで小数を2つ追加すると、間違った結果になるのはなぜですか?

可能性のある複製:
JavaScriptの数学は壊れていますか?

JSがこの単純な数学を台無しにするのはなぜですか?

console.log(.1 + .2)  // 0.3000000000000004
console.log(.3 + .6)  // 0.8999999999999999

最初の例は正しい結果よりも大きく、2番目の例はより小さくなっています。 ??? !!これをどのように修正しますか?操作を実行する前に、常に小数を整数に変換する必要がありますか?追加することだけを心配する必要がありますか(*および/はテストで同じ問題を抱えていないようです)?

私は多くの場所で答えを探しました。一部のチュートリアル(ショッピングカートフォームなど)では、問題が存在しないと想定し、値を加算するだけです。グルは、さまざまな数学関数に複雑なルーチンを提供するか、またはJSが合格すると「悪い仕事をします」と言いますが、まだ説明がありません。

54
Greg Perham

これはJSの問題ではなく、より一般的なコンピューターの問題です。浮動小数点数はすべてを10進数で適切に格納することはできません。なぜなら、それらは2進数でデータを格納するからです。例:

0.5 is store as b0.1 
but 0.1 = 1/10 so it's 1/16 + (1/10-1/16) = 1/16 + 0.0375
0.0375 = 1/32 + (0.0375-1/32) = 1/32 + 00625 ... etc

so in binary 0.1 is 0.00011... 

しかし、それは無限です。ある時点でコンピューターを停止する必要がある場合を除きます。したがって、この例で0.00011で停止すると、0.1ではなく0.09375になります。

とにかくポイントは、それは言語ではなくコンピューターに依存しているということです。言語に依存するのは、数字の表示方法です。通常、言語は数値を許容可能な表現に丸めます。どうやらJSはそうではありません。

そのため、あなたがしなければならないこと(メモリ内の数値は十分に正確です)は、JSにテキストに変換するときに数値を「適切に」丸めるように伝えることです。

sprintf関数を試して、数値の表示方法を細かく制御できます。

33
mb14

から 浮動小数点ガイド

なぜ0.1 + 0.2のような数字がナイスラウンド0.3に加算されず、代わりに0.30000000000000004のような奇妙な結果が得られますか?

内部的には、コンピューターは0.1、0.2、0.3などの数値を正確に表現できない形式(2進浮動小数点)を使用するためです。

コードがコンパイルまたは解釈されると、「0.1」はその形式で最も近い数値に既に丸められているため、計算が行われる前でも小さな丸め誤差が生じます。

このサイトには、詳細な説明と問題の修正方法に関する情報(および、それが問題であるかどうかを判断する方法)があります。

13

これはjavascriptのみの制限ではなく、すべての浮動小数点計算に適用されます。問題は、0.1および0.2および0.3がjavascript(またはCまたはJavaなど)浮動小数点数として正確に表現できないことです。したがって、表示される出力はその不正確さによるものです。

特に、2の累乗の特定の合計のみが正確に表現可能です。 0.5 = = 0.1b = 2 ^(-1)、0.25 = 0.01b =(2 ^ -2)、0.75 = 0.11b =(2 ^ -1 + 2 ^ -2)はすべて問題ありません。ただし、1/10 = 0.000110001100011..bは、2の累乗の無限の合計としてのみ表現でき、言語はある時点で切り捨てます。これらのわずかなエラーの原因となっているこのチョッピング。

8

すべての10進値を正確にバイナリで表現できるわけではないため、これはすべてのプログラミング言語で正常です。 すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと を参照してください

4
Henk Holterman

コンピューターが浮動小数点数を処理する方法に関係しています。詳細については、こちらをご覧ください: http://docs.Sun.com/source/806-3568/ncg_goldberg.html

1
Radu