2011-12-06 1 views
2
私はダブル/ float型に問題があることを知っている

ためのBigDecimalを使用するように、二重に使用することができ、金銭的なフィールドを表現するためのBigDecimalの代わりに/ダブルフロートを使用することをお勧めします。しかし、double/floatはより効果的で省スペースです。これは、Javaクラスの金融分野を表現するために、ダブル/フロートを使用するために許容です が、算術(すなわち、任意の算術前のBigDecimalにダブル/フロートを変換)と同じチェックの世話をするためにはBigDecimalを使用します。そして、私の質問はありますか?は、我々は、金融分野を保存し、算術

理由は、スペースを節約するためです。そして、私は本当にたくさんのプロジェクトが金貨の分野を表すためにdouble/floatを使っていることが分かります。

これにはどんな落とし穴がありますか? ありがとうございます。

+0

お金が消えないようにしない限り、金額を浮動小数点数/倍数で保存しないでください。 –

+0

私は1つの答えしか受け入れることができないので、多くの皆さんに感謝します。 – lostinmoney

答えて

5

いいえ、できません。

doubleは、2つの値xyを格納するのに十分であるとします。次に、それらを安全なBigDecimalに変換し、それらを複数にします。結果は正確ですが、乗算結果をdoubleに戻して保存すると、精度が失われる可能性があります。証明:

double x = 1234567891234.0; 
double y = 1234567891234.0; 
System.out.println(x); 
System.out.println(y); 

BigDecimal bigZ = new BigDecimal(x).multiply(new BigDecimal(y)); 
double z = bigZ.doubleValue(); 
System.out.println(bigZ); 
System.out.println(z); 

結果:

1.234567891234E12   //precise 'x' 
1.234567891234E12   //precise 'y' 
1524157878065965654042756 //precise 'x * y' 
1.5241578780659657E24  //loosing precision 

xyが正確であるだけでなく、乗算はBigDecimalを使用。しかし、doubleにキャストした後、我々は最下位の数字を失う。

+0

多くのありがとう。あなたの提案はどちらですか? 1.すべてのフィールドにBigDecimalを使用します。 2.これらのフィールドを表すにはlongを使用します。 – lostinmoney

+0

'double'は最大16桁の最長桁を格納できます。' long' - 18桁の0から始まります。 'double'は警告なしで最下位桁を削除し、他方は' long'をオーバーフローさせる可能性があります。精度と信頼性を本当に気にしているならば、必ずBigDecimalを使用してください(**実際に**下限と上限の値をあらかじめ知っていない限り)。結局のところ、速くて正しいプログラムを持っている方が良いでしょうか? –

+1

文字通り1ドルの金額に別の金額を乗算すると、データ型の選択よりも大きな問題が発生します。 。 。 – ruakh

2

longは、double/floatよりはるかに良い選択です。

BigDecimalタイプを使用して、実際のボトルネックになることをあなたはよろしいですか?

+0

これはセントを扱う単純な金銭的なアプリケーションではないので。少なくとも5小数点を維持するために必要な価格や金額があるかもしれません。 – lostinmoney

+0

+1。しかし、明確にするには、 '' int''や '' long'sを使うと、1つよりも少ない通貨単位をサポートするために、何らかの定数(通常は100または1000)を使わなければなりません。たとえば、$ 1を1000L、1¢を10Lと表すことができます。これを独自のデータ型で囲むことは良い考えです。 – ruakh

0

ピットの秋には、フロート/ダブルス精度を失うことなく、すべての値を格納できないということです。 BigDecimalを使用して計算中に精度を保持しても、最終製品をフロート/ダブルとして保存しています。

私の経験では、これを「適切に」解決するには、数千ドルを表す整数(例:Long)として金額を保存することが必要です。これにより、ほとんどのタスクに十分な解像度が得られます。浮動小数点/倍精度の使用の問題を踏み出しながら、利息の授受を行っています。追加の「ボーナス」として、フロート/ダブルスとほぼ同じ量のストレージが必要です。

2

あなたのプロジェクトによって、受け入れ可能なものは異なります。いくつかのプロジェクトではdoubleとlongを使用することができます。しかし、他のプロジェクトでは、これは受け入れられないと考えられています。倍数として、70,000,000,000,000.00までの値を(米国の国家負債より大きい)セントを表すことができ、固定された場所で長く90,000,000,000,000,000.00を正確に表すことができます。

あなたはハイパーインフレ通貨(いずれにせよ悪いアイデア)に対処する必要がありますが、何らかの理由でまだBigDecimalのを使用し、すべてのセントを説明するために必要がある場合。

あなたは、二重または長いかのBigDecimalを使用する場合は、その結果を丸める必要があります。これを行う方法は各データ型によって異なります。異なる演算の丸めと精度を指定する必要があるため、BigDecimalは最もエラーが発生しにくいものです。ダブルまたはロングで、あなたは自分のデバイスに任せられます。

2

通貨を含む可能性のあるすべての演算にBigDecimal以外を使用することもお勧めします。

常にBigDecimalのStringコンストラクタを使用するようにしてください。どうして? JUnitテストに次のコードを試してみてください。

assertEquals(new BigDecimal("0.01").toString(), new BigDecimal(0.01).toString()); 

あなたは次のような出力が得られます。

expected:<0.01[]> but was <0.01[000000000000000020816681711721685132943093776702880859375]> 

真実は、あなたが「ダブル」量と正確に 0.01 を格納することはできません。 BigDecimalには、必要な番号が格納されています。正確にはです。

BigDecimalは不変であることに注意してください。

BigDecimal amount = new BigDecimal("123.45"); 
BigDecimal more = new BigDecimal("12.34"); 
amount.add(more); 
System.out.println("Amount is now: " + amount); 

をしかし、出力結果は次のようになります。以下は、コンパイルされます

額は今です:あなたは新しい(またはに結果を割り当てる必要があるためです123.45

同じ)BigDecimal変数。言い換えれば

amount = amount.add(more) 
+0

BigDecimalのベストプラクティスに感謝します。 – lostinmoney

0

doubleの使用のみが小数点値にある場合は、[はい、あなたはいくつかの条件の下で行うことができますあなたの値が15以下で持っていないことを保証することができた場合小数点以下を入力してdouble(精度は53ビット)に変換し、doubleを15桁の精度(またはそれ以下)で小数点に戻すと、David Matulaの定理のアプリケーションから元の値、つまり損失はありません彼の記事In-and-out conversionsで証明されています。この結果を適用するには、correct roundingで変換を行う必要があります。

注しかしdoubleは最良の選択ではないかもしれないこと:小数点以下の数桁(P)との金銭的価値は、一般浮動小数点でない表現されているが、固定点であり、この場合には、変換します10^pのスケーリングを持つ整数に値を設定し、この整数を格納することが推奨されます。