2012-01-05 14 views
3

私は長年にわたり合理的にうまくいった時間計算機を持っています。しかし、いつも気になっていたことは、小数点以下の秒数を使用すると、結果が浮動小数点の「エラー」になる可能性があるということでした。だから、私は最近this BigDecimal libraryを使用するように切り替えました。不正確な除算結果

今、数学的なエラーが発生しています。今日受け取ったバグレポートの単純化されたテストケースです:27436/30418は、0.9019659412190151の代わりに1を返しています。私の問題を説明するために

、ここでChromeのJavaScriptコンソールセッションです:あなたが見ることができるように

> first = 27436 
27436 
> second = 30418 
30418 
> first/second 
0.9019659412190151 // expected result, but using JS numbers, not BigDecimals 
> firstB = new BigDecimal(first.toString()) 
o 
> secondB = new BigDecimal(second.toString()) 
o 
> firstB/secondB 
0.9019659412190151 // this is a JS number, not a BigDecimal, so it's susceptible to the problems associated with floating-point. 
> firstB.divide(secondB) 
o // BigDecimal object 
> firstB.divide(secondB).toString() 
"1" // huh? Why 1? 
> firstB.divideInteger(secondB).toString() 
"0" 

divide()方法は、私が期待する結果を生成されていません。私は何をする必要がありますか?

更新

コメントに応じて、さらに詳しい説明があります。

まず、BigDecimalを使用することは過度の使用であるとの意見がいくつか出されました。そうかもしれませんが、私はその決定を下す前にもっと詳細が必要だと思います。このアプリはtime calculatorなので、私はBigDecimalに切り替えるためにプッシュしたものがいくつかあります。まず、これは電卓なので、ユーザーに正解を示すことが重要です。ユーザーが0.1 s + 0.2 sと入力した場合、回答は0.3 sであると予想されます.Javascriptが表示する回答ではありません(0.30000000000000004)。

JSで使用できる精度を超えて精度を制限したくないので、ユーザーに必要な最大精度がわからないため、整数を使用できます。ほとんどの場合、小数点以下の秒を使用することはありませんが、私が受け取った電子メールから判断すると、いくつかあります。私は現在、すべての時間を秒として内部的に保管しています。

誰かが、数字を正確な分数として保存することを提案しました。残念ながら、私はそれが何を意味するのか分かりません。多分私は数学についてあまり知りません。私は自分の数学図書館を転がすには十分知らない。そのため私はBigDecimalを使用しています。それは長い間されているので、私は問題がBigDecimalのバグに起因すると言っていることを躊躇しています。私はむしろそれが私がそれを使用している方法のバグだと思う。

最後に、私は具体的にBigDecimalに結びついていません。私は、私の不十分な数学スキルでそれらを使うことができるならば、他の提案には開いています。

+1

おそらく、それは精度と関係があります。同様に、精度が小さすぎる場合、最も近い整数に丸められます。また、単純に浮動小数点エラーのためにBigDecimalを使うのは残念です。また、数値を正確な分数として保存することもできます。 – karnok

+0

ええ、BigDecimalを使用すると、あまりにも過剰な私のように見えます。特に、* time *のような固定精度の計算を行う場合は、整数(秒?ミリ秒ですか?)を使用してから、適切な変換を行います。 – redShadow

+0

0.1は、丸め誤差のかなり大きな違いです。また、問題は火かき棒のままです。おそらくバグレポートを提出したいと思うかもしれません。 –

答えて

4

私はまだどのプロダクションコードでもBigDecimalを使用していませんが、この質問は面白いので、私は試してみます。除算関数のパラメータとしてMathContextが必要であることは間違いありません。ここで私はあなたの例に基づいて、何をしたかである:

科学的なモード出力で100桁を使用するためにはBigDecimalを伝えコンテキストを作成
console.log(firstB.divide(secondB, new MathContext(100)).toString()); 

0.9019659412190150568742192123085015451377473864159379314879347754618975606548754027220724570977710566 

異なる出力モードを制御するオプションもありますPLAINSCIENTIFICおよびENGINEERING +さまざまな丸めモード。jsfiddle

全例更新: デフォルトの出力フォーマットはSCIENTIFIC、ないPLAINです。例here

アップデート2:小さな性能試験hereを作成し は、BigDecimalのように見えますが、ネイティブのJavaScript部門の約10000倍遅くなります。

+0

ありがとうございます。 BigDecimalのコピーを最新版に更新した後、事態が始まりました。 –

+0

さて、パフォーマンスはあまり重要ではありません。私は1回の除算操作しか行っていません。全体として、私のアプリはユーザーの入力に応じて約5回の計算を行いますので、速度の違いは目立たないでしょう。おそらく数msの違いを話しています。 –

関連する問題