1

を使用してDecimalFormatいるときに、固定小数点パターンで数値を丸めるときの動作に戸惑いました。より具体的にするために:

double n = 2082809.080589735D;

// Output the exact value of n
System.out.println("value:       " + new BigDecimal(n).toPlainString());

System.out.println("double:      " + n);

DecimalFormat format = new DecimalFormat("0.00000000");

System.out.println("format:      " + format.format(n));
System.out.println("format (BD): " + format.format(new BigDecimal(n)));

このスニペットの出力は次のとおりです。

value:       2082809.080589734949171543121337890625
double:      2082809.080589735
format:      2082809.08058974
format (BD): 2082809.08058973

最初の出力行から、実際の値がと( )の中間点を下回っていることがわかります。それにもかかわらず、引数が指定された場合、値は切り上げられます。2082809.080589732082809.08058974...49...DecimalFormatdouble

その他の値は切り捨てられます。

value:       261285.2738465850125066936016082763671875
double:      261285.273846585
format:      261285.27384658
format (BD): 261285.27384659

これはすべての場合に発生するわけではありません。

value:       0.080589734949171543121337890625
double:      0.08058973494917154
format:      0.08058973
format (BD): 0.08058973

value:       0.2738465850125066936016082763671875
double:      0.2738465850125067
format:      0.27384659
format (BD): 0.27384659

aのフォーマットされた文字列は、問題の実際の数学的値ではなく、の線に沿って生成された不正確な10進値に基づいて、半偶数丸めdoubleを使用して丸められているように見えます。フォーマットされた精度がタイプによって提供される精度に非常に近い(またはそれ以上)場合、物事はややランダムになり始めます。Double.toString()doubledouble

上記のすべてのケースで、対応するフォーマットをフォーマットするBigDecimalと、期待どおりに丸めが実行されるようです。

DecimalFormatこの場合の適切な動作を説明する仕様を見つけることができませんでした。

  • この動作はどこかに文書化されていますか?

  • 正確さの観点から、実際の数学的値を四捨五入することは望ましいことではないでしょうか。

    書く人1.0...35は(素朴に?)それが丸められることを期待するだろうと理解しています1.0...41.0...35、Javaで利用可能なプリミティブデータ型では表現できないかもしれません...

編集:

オラクルにレポートを提出しました。この問題を修正または明確化できることを願っています。

4

3 に答える 3

1

これは明らかに、Java8で修正され既知の問題でした。

DecimalFormatJava 8では、開発者が選択した形式に関係なく、常に正しく丸めを実行することになっています。当然、これはJava 7と比較した場合、わずかに互換性のない動作になります。これが重要かどうかは、各アプリケーションの詳細によって異なります。

于 2014-03-18T22:39:08.050 に答える
0

Java言語仕様によると、JavaはIEEE 754-1985を使用しますが、(IEEE754-2008と想定されるコメントから)

浮動小数点型はfloatとdoubleであり、概念的には、単精度32ビットおよび倍精度64ビット形式のIEEE 754値と、IEEE Standard for Binary Floating-Point Arithmetic、ANSI/IEEEで指定されている操作に関連付けられています。標準754-1985(IEEE、ニューヨーク)。

を使用setRoundingMode()DecimalFormatて、丸め動作を指定します。

この動作はどこかに文書化されていますか?

DecimalFormatのjavadocと、 RoundingMode およびIEEE 754-1985およびJLS(この回答の最初の政治家)の詳細を参照してください。

文書化されているように、デフォルトは半偶数丸めモードです。HALF_EVEN

public static final RoundingMode HALF_EVEN

両方のネイバーが等距離にある場合を除き、「最も近いネイバー」に向かって丸める丸めモード。この場合、偶数のネイバーに向かって丸めます。破棄された小数部の左側の桁が奇数の場合、RoundingMode.HALF_UPと同様に動作します。偶数の場合、RoundingMode.HALF_DOWNと同様に動作します。これは、一連の計算に繰り返し適用された場合に累積エラーを統計的に最小化する丸めモードであることに注意してください。「バンカーの丸め」と呼ばれることもあり、主に米国で使用されています。この丸めモードは、Javaのfloatおよびdouble演算に使用される丸めポリシーに類似しています。

于 2013-02-17T13:15:13.660 に答える
0

これは、二重の丸めが原因である可能性があります。

「double」とマークされた出力は、16桁に正しく丸められているように見えます。「フォーマット」とマークされた出力は、16桁の値から丸められたように見えます(半分から偶数に丸められます)。

(これを確認するには、さらに多くの例を見る必要があります。)

于 2013-02-18T15:56:16.080 に答える