0

double 値の小数点以下 2 桁を保持する方法をいくつか見つけようとしています。現在、以下の5つの方法を試しました。

  • java.math.BigDecimal を使用
  • java.text.DecimalFormat を使用
  • java.text.NumberFormat を使用する
  • java.util.Formatter を使用する
  • String.format を使用

これら 5 つの方法の結果は、基本的に一貫しています。ただし、一部のシナリオでは、java.math.BigDecimal は他の 4 つのメソッドとは異なる結果になります。

たとえば、double 値100.0050Dを使用します。

java.math.BigDecimal を使用すると、私のコードでは 100.00 が返されます。ただし、他の 4 つのメソッドは 100.01 を返します。結果は矛盾しています。

実際には、RoundingMode.HALF_UPが使用されます。ここに私の質問があります:

以下のコードで、java.math.BigDecimal を使用して double 値で小数点以下 2 桁を保持するために見逃したものはありますか?

それとも、クラス java.math.BigDecimal の小さな欠陥ですか?

これで私を助けてください。前もって感謝します。

さらに、さまざまなJDKバージョンで異なるかどうかはわかりません。使用したJDKのバージョンが1.7.0_25であるという情報を提供するだけです。

コードは次のとおりです。

public final class PrecisionTest {

    private PrecisionTest() {
    }

    public static String format1(double value) {

        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(2, RoundingMode.HALF_UP);
        return bd.toString();
    }

    public static String format2(double value) {

        DecimalFormat df = new DecimalFormat("0.00");
        df.setRoundingMode(RoundingMode.HALF_UP);
        return df.format(value);
    }

    public static String format3(double value) {

        NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setMaximumFractionDigits(2);
        nf.setMinimumFractionDigits(2);
        nf.setRoundingMode(RoundingMode.HALF_UP);
        nf.setGroupingUsed(false);
        return nf.format(value);
    }

    public static String format4(double value) {
        return new Formatter().format("%.2f", value).toString();
    }

    public static String format5(double value) {

        return String.format("%.2f", value).toString();
    }
}

簡単なテスト コードは次のとおりです。

public class Main {

    public static void main(String[] args) {   

        double[] testData = new double[] { 100.123D, 1234567.897D, 100.0050D,   
                80.0051D,-100245.3658D};   

        for (double value : testData) {   
            System.out.println(PrecisionTest.format1(value));   
            System.out.println(PrecisionTest.format2(value));   
            System.out.println(PrecisionTest.format3(value));   
            System.out.println(PrecisionTest.format4(value));   
            System.out.println(PrecisionTest.format5(value));   
        }   
    }   
}
4

2 に答える 2

4

100.005 の double 表現は正確ではなく、100.005 よりわずかに小さいです。

scala> new java.math.BigDecimal(100.0050)
res0: java.math.BigDecimal = 100.0049999999999954525264911353588104248046875

したがって、スケールと丸めモードを設定すると、100.00 に切り捨てられます。

一方、String を使用して BigDecimal を作成すると、期待どおりに機能します。

scala> new java.math.BigDecimal("100.0050")
res2: java.math.BigDecimal = 100.0050

scala> res2.setScale(2, java.math.RoundingMode.HALF_UP).toString
res3: java.lang.String = 100.01
于 2013-10-27T09:06:37.250 に答える
2

double[] testData = 新しい double[] { 100.123D、1234567.897D、100.0050D、
80.0051D、-100245.3658D};

問題はここにあります。BigDecimal とはまったく関係ありません。これらの数値は、浮動小数点では正確に表すことができません。値のString表現から BigDecimal を初期化してみてください。

于 2013-10-27T09:20:53.150 に答える