web-dev-qa-db-ja.com

DecimalFormatおよびDouble.valueOf()

Double値の小数点以下の不要な記号を削除しようとしています。私はそれをこのようにやっています:

_DecimalFormat format = new DecimalFormat("#.#####");
value = Double.valueOf(format.format(41251.50000000012343));
_

しかし、このコードを実行すると、次のようにスローされます。

_Java.lang.NumberFormatException: For input string: "41251,5"
    at Sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.Java:1224)
    at Java.lang.Double.valueOf(Double.Java:447)
    at ...
_

ご覧のとおり、Double.valueOf()は_"11.1"_のような文字列でうまく機能しますが、_"11,1"_のような文字列では窒息します。これを回避するにはどうすればよいですか?次のようなよりエレガントな方法はありますか

_Double.valueOf(format.format(41251.50000000012343).replaceAll(",", "."));
_

DecimalFormatクラスのデフォルトの小数点記号値をオーバーライドする方法はありますか?他に何か考えはありますか?

12
folone

沿って

私のdouble値の小数点の後の不要な記号を取り除きます

あなたは実際にあなたが例えばに丸めたいという意味ですか?小数第5位?次に、

_value = Math.round(value*1e5)/1e5;
_

(もちろん、他の数字を本当に切り落としたい場合は、Math.floor(value*1e5)/1e5もできます)

79
Tobias Kienzler

問題は、10進形式が値をローカライズされた文字列に変換することです。ロケールのデフォルトの小数点は「,」であると思います。これは、フランス語のロケールまたは世界の他の地域でよく発生します。

基本的にあなたがする必要があるのは「。」でフォーマットされた日付を作成することです。 Double.valueOfが読み取れるように区切り文字。コメントで示されているように、Double.valueOfを使用する代わりに、同じ形式を使用して値を解析することもできます。

DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
symbols.setDecimalSeparator('.');
DecimalFormat format = new DecimalFormat("#.#####", symbols);
value = format.parse(format.format(41251.50000000012343));
24
Chris Dail

書式設定文字列が小数点記号として.を使用しているのに対し、例外が,を要求しているという事実は、ロケールの問題を示しています。つまり、DecimalFormatは、Double.valueOfが期待するものとは異なるロケールを使用して数値をフォーマットしています。

一般に、特定のロケールに基づいてNumberFormatを作成する必要があります。

Locale myLocale = ...;
NumberFormat f = NumberFormat.getInstance(myLocale);

DecimalFormat のJavaDocsから:

デフォルトのロケールを含む特定のロケールのNumberFormatを取得するには、getInstance()などのNumberFormatのファクトリメソッドの1つを呼び出します。 NumberFormatファクトリメソッドはDecimalFormat以外のサブクラスを返す可能性があるため、通常、DecimalFormatコンストラクタを直接呼び出さないでください。

ただし、 BalusCが指摘しているように 、doubleをStringとしてフォーマットしてから、Stringを解析してdoubleに戻そうとすると、コードの臭いがかなり悪くなります。固定精度の10進数(金額など)を期待しているが、doubleは浮動小数点数であるため、多くの値(0.1など)を使用できないため、問題が発生していると思われます。ダブル/フロートとして正確に表現されます。この場合、固定精度の10進数を処理する正しい方法は、 BigDecimal を使用することです。

6
matt b

Locale.getDefault()を使用して、システムの小数点記号を取得します。これも設定できます。セパレーターは通常、数千のセパレーターとして使用されるため、同時に異なるセパレーターを使用する必要はありません。2.001.000,23<=> 2,001,000.23

5
Tobias Kienzler

本当の解決策は次のとおりです。正確にカウントする必要があるものには浮動小数点数を使用しないでください。

  • 通貨を扱っている場合は、2倍のドルを使用せず、整数のセントを使用してください。
  • 時間を処理していて、15分と10分間隔を数える必要がある場合は、整数の分を使用します。

浮動小数点数は、ほとんどの場合、実際の値の近似値です。これらは、物理量(最高の精度)の測定と計算、および統計的アーティファクトに適しています。

浮動小数点を桁数に丸めることにだまされるのはコードの臭いです。それは無駄であり、コードがすべての場合に正しく機能することを本当に確信することはできません。

4
PaulMurrayCbr

'_,_'の代わりに '_._'の場合は、ロケールを変更する必要があります。

小数点以下の桁数については、setMaximumFractionDigits(int newValue)を使用してください。

残りについては、 javadocを参照

3
Maxime ARNSTAMM

ローカルでは、小数点以下の区切りとしてカンマ「、」を使用しているようです。「。」を取得するには小数点として、次のように宣言する必要があります。

DecimalFormat dFormat =new DecimalFormat("#.#", new DecimalFormatSymbols(Locale.ENGLISH));
3
Vaibhav Barad

これにいくらか関連していますが、質問への回答ではありません。doubleとfloatの代わりにBigDecimalに切り替えてみてください。私はそれらのタイプの比較で多くの問題を抱えていました、そして今私はBigDecimalで行くのは良いことです。

2
Joao Coelho

double/Doubleの内部表現をそのように変更することはできません。

(人間の)表現を変更したい場合は、Stringのままにしてください。したがって、そのDouble#valueOf()を離れて、プレゼンテーションでDecimalFormat#format()String結果を使用します。それを使って計算をしたい場合は、DoubleDouble#valueOf()を使用していつでも実際のDecimalFormatに戻すことができます。

ちなみに、あなたの不満のとおり私は私のdouble値の小数点の後の不要な記号を取り除こうとしていますあなたは浮動小数点数の内部を認識しています ?プレゼンテーション層でフォーマットされていないdoubleを使用しているようで、平均的なUIではDecimalFormatを使用してDouble

2
BalusC

私のコード関数:

 private static double arrondi(double number){
         DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
         symbols.setDecimalSeparator('.');
         DecimalFormat format = new DecimalFormat("#.#####", symbols);
         return Double.valueOf(format.format(number));
     }
0
Neoray