17

double値の10進区切り記号の後の不要な記号を削除しようとしています。私はそれをこのようにやっています:

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

4

10 に答える 10

88

double 値の小数点区切り記号の後に不要な記号を削除する

たとえば、小数点以下 5 桁に丸めたいということですか。次に、使用するだけです

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

(もちろんMath.floor(value*1e5)/1e5、他の桁を切り捨てたい場合も可能です)

編集

この方法 (または浮動小数点の丸め) を使用するときは十分に注意してください。265.335 のような単純なものでは失敗します。265.335 * 100 (2 桁の精度) の中間結果は 26533.499999999996 です。これは、265.33 に切り捨てられることを意味します。浮動小数点数から実数の 10 進数への変換には固有の問題があります。ここでEJPの回答を参照してください https://stackoverflow.com/a/12684082/144578 - Javaで数値を小数点以下n桁に丸める方法

于 2010-04-22T13:25:34.867 に答える
24

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

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

DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
symbols.setDecimalSeparator('.');
DecimalFormat format = new DecimalFormat("#.#####", symbols);
value = format.parse(format.format(41251.50000000012343));
于 2010-04-22T13:25:37.647 に答える
6

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

于 2010-04-22T13:19:09.997 に答える
6

例外がロケールの問題を指摘している間、フォーマット文字列が.小数点として使用されるという事実。,つまり、DecimalFormat は、Double.valueOf が期待するものとは異なるロケールを使用して数値をフォーマットしています。

NumberFormat一般に、特定の Locale に基づいてを構築する必要があります。

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

DecimalFormatの JavaDocs から:

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

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

于 2010-04-22T13:20:36.740 に答える
4

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

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

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

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

于 2016-05-30T06:26:34.327 に答える
4

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

DecimalFormat dFormat =new DecimalFormat("#.#", new DecimalFormatSymbols(Locale.ENGLISH));
于 2015-09-09T14:59:38.093 に答える
3

' ,' ではなく ' .' の場合は、ロケールを変更する必要があります。

小数点以下の桁数については、 を使用しますsetMaximumFractionDigits(int newValue)

残りについては、 javadoc を参照してください

于 2010-04-22T13:20:19.427 に答える
2

これに多少関連していますが、質問への回答ではありません: double と float の代わりに BigDecimal に切り替えてみてください。私はこれらの型の比較で多くの問題を抱えていましたが、今では BigDecimal を使用することにしました。

于 2010-04-22T20:46:21.453 に答える
2

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

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

ところで、あなたの苦情によると、 double 値の小数点区切り記号の後に不要な記号を取り除こうとしていますが、浮動小数点数の内部構造を知っていますか? プレゼンテーション レイヤーでフォーマットされていない double を使用していて、平均的な UI を使用DecimalFormatすると、Double.

于 2010-04-22T13:12:02.757 に答える