2009-08-31 15 views
52

私はlongを使って自分のクラスを通貨にしようとしていましたが、代わりにBigDecimalを使うべきです。誰かが私を助けてくれるの? BigDecimalをドル通貨に使用する最良の方法は、最低でもセントで小数点以下2桁未満にするなどです。BigDecimalのAPIは膨大で、どのメソッドを使用するかわかりません。また、BigDecimalは精度が高いですが、doubleを通過するとすべてが失われるわけではありませんか? BigDecimal(24.99)を新規作成すると、doubleを使用する場合とどう違うのですか?代わりにStringを使用するコンストラクタを使用する必要がありますか?あなたがdouble精度に制限されている場合はBigDecimalを使って通貨を扱う

+0

すべてが正常に見えるが、最後に1つの事のために短いクリップを見てください - あなたがBigDecimalのインスタンス上setScale()を使用する場合、後で追加のためにそれを使用する場合は特に、丸めを提供n + 1の係数。ここで、nは有効桁数です。たとえば、丸め係数を3に設定すると、0.043 + 0.043では0.08ではなく0.09が返されます(丸め/格納に2桁の有効数字を選択した場合)。 –

+0

上記の例では、2桁の有効桁を選択し、加算前に丸め(中間演算として)を実行した場合、0.04 + 0.04 = 0.08を得ます。 –

+0

価格から削除されるパーセンテージを格納する変数がBigDecimalまた? – mk12

答えて

64

を使用しているいくつかのヒントです:あなたはそれが(マネーの値は、多くの場合、これを必要とする)を提供する精度が必要な場合

  1. 使用BigDecimal計算のため。
  2. NumberFormatクラスを使用して表示します。このクラスは、異なる通貨の金額に関するローカリゼーションの問題を処理します。ただし、プリミティブのみを使用します。したがって、doubleへの変換による小さな精度の変更を受け入れることができれば、このクラスを使用することができます。
  3. NumberFormatクラスを使用する場合は、BigDecimalインスタンスでscale()メソッドを使用して、精度と丸め方法を設定します。

PS:あなたが不思議に思っていた場合は、BigDecimal is always better than double, when you have to represent money values in Javaです。

PPS:

BigDecimalインスタンス

これはBigDecimal provides constructors to take in primitive values以来、非常に簡単です、とStringオブジェクトを作成します。あなたはそれらを使用することができますpreferably the one taking the String object。例えば、BigDecimalインスタンス

を表示

BigDecimal modelVal = new BigDecimal("24.455"); 
BigDecimal displayVal = modelVal.setScale(2, RoundingMode.HALF_EVEN); 

あなたがsetMinimumFractionDigitssetMaximumFractionDigits方法が表示されているデータの量を制限するために呼び出して使用することができます。

NumberFormat usdCostFormat = NumberFormat.getCurrencyInstance(Locale.US); 
usdCostFormat.setMinimumFractionDigits(1); 
usdCostFormat.setMaximumFractionDigits(2); 
System.out.println(usdCostFormat.format(displayVal.doubleValue())); 
+3

特に番号2で同意します。表示(表示用の書式設定)をモデル(BigDecimal)とは別にします。特定のデータ型を扱うカスタムjava.text.Formatを書くことができます。 –

+0

NumberFormatではなくDecimalFormatを意味していませんか? – mk12

+0

@ Mk12のいずれかを使用できます。 DecimalFormatは、書式設定をより詳細に制御する場合に使用されます。 NumberFormatが適用しないapplyPattern()メソッドを提供します。 –

1

1)、BigDecimal Sを使用する1つの理由は、double sから作成されたBigDecimal秒での操作を実現することです。

2)BigDecimalは、任意の精度整数のスケーリングされていない値と非負の32ビット整数スケールで構成され、doubleはプリミティブ型doubleの値をオブジェクトにラップします。タイプDoubleのオブジェクトには、型double

3である)それは何の違い

を作るべきではありませんあなたは$と精度で何の困難を持つべきではない単一のフィールドが含まれています。それを行うための1つの方法は、ここでSystem.out.printf

0

BigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP)は、セントの小数点以下2桁まで切り上げたい場合に使用します。あなたが計算をするときにエラーを四捨五入することに注意してください。金額の丸めを行うときは、一貫性が必要です。すべての計算が終了したら、最後に一度丸めを行うか、計算を行う前に各値に丸めを適用します。どちらを使うかはあなたのビジネス要件に左右されますが、一般的に、最終的に丸めをすることは私にはもっと良い意味合いがあるようです。

お金の値をBigDecimalに設定すると、Stringを使用します。 doubleを使用すると、末尾に浮動小数点値が付きます。これは、値がバイナリ形式で表現されている方法に関するコンピュータのアーキテクチャに起因します。double/float

+10

金融アプリケーションの場合、ROUND_HALF_EVENはバイアスを回避するため、最も一般的な丸めモードです。 –

+0

偏見を避けることについての良い点。それを達成するためにそれが働いたのか分からなかった。 –

+0

@マイケル:チップをありがとう。私はそれを知らなかった。私はバイアス/累積誤差をどのように最善に扱うのかといつも考えました。今日何か新しいことを学びました。 :) –

0

javapractices.comでこれを行う方法の広範な例があります。具体的にはMoneyクラスを参照してください。これは、BigDecimalを直接使用するよりも簡単に金銭計算を行うことを目的としています。

このMoneyクラスのデザインは、表現をより自然にするためのものです。例えば:

if (amount.lt(hundred)) { 
cost = amount.times(price); 
} 

WEB4Jツールはもう少し研磨MoneyクラスよりDecimalと呼ばれる同様のクラスを有しています。

28

私はMoney Patternに関する少しの研究をお勧めします。 Martin Fowlerの著書「Analysis pattern」ではこれについてより詳しく説明しています。

用法に来
public class Money { 

    private static final Currency USD = Currency.getInstance("USD"); 
    private static final RoundingMode DEFAULT_ROUNDING = RoundingMode.HALF_EVEN; 

    private BigDecimal amount; 
    private Currency currency; 

    public static Money dollars(BigDecimal amount) { 
     return new Money(amount, USD); 
    } 

    Money(BigDecimal amount, Currency currency) { 
     this(amount, currency, DEFAULT_ROUNDING); 
    } 

    Money(BigDecimal amount, Currency currency, RoundingMode rounding) { 
     this.amount = amount; 
     this.currency = currency; 

     this.amount = amount.setScale(currency.getDefaultFractionDigits(), rounding); 
    } 

    public BigDecimal getAmount() { 
     return amount; 
    } 

    public Currency getCurrency() { 
     return currency; 
    } 

    @Override 
    public String toString() { 
     return getCurrency().getSymbol() + " " + getAmount(); 
    } 

    public String toString(Locale locale) { 
     return getCurrency().getSymbol(locale) + " " + getAmount(); 
    } 
} 

BigDecimalとは対照的に、あなたはMoneyオブジェクトを使用して、すべての金銭を表します。大きな小数点としてのお金を表すことは、あなたがそれを表示する場所ごとにお金をフォーマットすることを意味します。ディスプレイの標準が変わったかどうかを想像してみてください。あなたはその場所全体の編集をしなければならないでしょう。 Moneyパターンを使用する代わりに、お金の書式を1か所に集約します。

Money price = Money.dollars(38.28); 
System.out.println(price); 
+2

この問題の1つの問題は、すべての通貨が金額の前のシンボルにデフォルトで設定されているわけではなく、間にスペースがあるわけではありません。それは、自分自身の一部でなければならないことです。 –

7

または、JSR-354を待ちます。すぐにJavaマネーと通貨APIが来ます!

+2

あなたはコメントを残さずに良いアドバイスをチェックする人々が嫌いではありません! –

+2

#ジェイムズドリンクそれはそうではありません。 JSR 354はすぐに独立したライブラリとしてリリースされる予定です。元の計画はJava 9を待つことでしたが、中間のライブラリはすぐにリリースされます –

+3

すぐにJavaの用語で...笑。 – Rob

1

プリミティブ数値型は、単一の値をメモリに格納するのに便利です。しかし、double型とfloat型を使用した計算を扱う場合、丸めに問題があります。これは、メモリ表現が値に正確にマッピングされないために起こります。たとえば、二重の値は64ビットとみなされますが、Javaではすべての64ビットが使用されるわけではありません。したがって、float型またはdouble型の値を一緒に追加すると、間違った値に到達する可能性があります。

https://youtu.be/EXxUSz9x7BM

0
NumberFormat.getNumberInstance(java.util.Locale.US).format(num); 
+0

私はこの答えの単純さが好きですが、最終的なゼロを落とす1.50の代わりに1.5を返します。 – JesseBoyd