質問: 以下の値が、**3.9000000000000004**になってしまいます。 ``` $('#target').val(3 * 1.3); ``` これを**3.9**と正しく計算する方法をご教授ください。
回答: JavaScriptで`1.3`というリテラルは 1.3 という十進数の浮動小数点数の値では**ありません**。 ``` console.log((1.3).toFixed(20)); ``` 実行結果 つまり、`1.3`と書いた時点で**正確ではない**ので、その計算結果も正確であるとは限りません。JavaScriptの数値は、-9007199254740991から9007199254740991までの整数と、2倍を繰り返すと整数になる一部の小数点数だけが正確に表現可能であり、それ以外は近似値であって正確な計算はできないのです。 これは、JavaScriptでの数値がIEEE 754-2008の64ビット倍精度浮動小数点数を表現しているためであり、詳しくは倍精度浮動小数点数について調べてください。 では、どうするのかというと、いくつかの方法があります。 ### 結果を意味のある精度で丸める。 倍精度浮動小数点数では10進数表記の精度は15桁ほどです。逆に言うと`1.3`という数値は15桁までは正確であるとも言えます。ただ、精度の桁数計算(計算結果によって何桁までは正確であると判断するか)は複雑です。どちらかというと、意味がある桁数までしか見ないとした方が有用です。今回の場合は、小数点数2桁目以降は関心が無いとして、丸めることにします。丸めるには`Math.round()`がありますが、整数になってしまいます。ですので、10倍してから10で割ります。 ``` $('#target').val(Math.round((3 * 1.3) * 10) / 10); ``` 気をつけて欲しいのは`3.9`も依然として、 3.9 という十進数の浮動小数点数の近似値にすぎないと言うことに気をつけてください。 実際は、表示の時だけ丸めた方が有用と思います。 ### 整数として計算する。 `1.3`を10倍にして整数にしてしまえば精度の問題は解決します。-9007199254740991から9007199254740991までの整数は正確に計算できるからです。 ``` $('#target').val((3 * Math.round(1.3 * 10)) / 10); ``` 実際は、最初から最後まで整数としてデータを扱った方が良いと思います。 ### 任意精度小数点数が扱えるライブラリを使う。 十進数を任意の制度で計算するためのライブラリがあります。それらを使えば問題なく計算できます。ライブラリはいくつかありますが、decimal.jsを使った場合は、次のようになります。 ``` $('#target').val(new Decimal('3').mul(new Decimal('1.3')).toNumber()); ``` 任意精度小数点数は処理が重くなりがちなので、本当に必要な場合は使わない方が良いでしょう。また、精度に関する知識が無いと、正確な精度を把握できません。 ### その他 `1.3`を13/10という有理数として計算するというのもあります。有理数ライブラリもあるようですので、探してみてください。ただし、有理数計算は総じて重いです。