16

JavaBigDecimalがこれほど苦痛を伴うのはどうしてでしょうか。

Double d = 13.3D;

BigDecimal bd1 = new BigDecimal(d);
BigDecimal bd2 = new BigDecimal(String.valueOf(d));


System.out.println("RESULT 1: "+bd1.toString());
System.out.println("RESULT 2: "+bd2.toString());

RESULT 1: 13.300000000000000710542735760100185871124267578125
RESULT 2: 13.3

結果1が望まれる状況はありますか? Java 1.5 でメソッドが変更されたことは知っていますtoString()が、これは意図した結果でしたか?

また、それBigDecimalにはdoubleValue()etc があることも理解していますが、私が使用しているライブラリは a を便利に使用しており、toString()それを変更することはできません :-(

乾杯。

4

5 に答える 5

51

ええと、APIはコンストラクターのこの明らかな矛盾に対処しますBigDecimal(double val)

  1. このコンストラクターの結果は、多少予測できない場合があります。Javaで新しいBigDecimal(0.1)を書き込むと、0.1に正確に等しいBigDecimal(スケールなしの値1、スケール1)が作成されると思われるかもしれませんが、実際には0.1000000000000000055511151231257827021181583404541015625に等しくなります。これは、0.1を正確にdoubleとして(または、さらに言えば、任意の有限長の2進数として)表すことができないためです。したがって、コンストラクターに渡される値は、外観にもかかわらず、0.1と正確に等しくはありません。

  2. 一方、Stringコンストラクターは完全に予測可能です。新しいBigDecimal( "0.1")を作成すると、予想どおり、0.1に正確に等しいBigDecimalが作成されます。したがって、一般的には、これよりもStringコンストラクターを使用することをお勧めします。

  3. doubleをBigDecimalのソースとして使用する必要がある場合、このコンストラクターは正確な変換を提供することに注意してください。Double.toString(double)メソッドを使用してdoubleをStringに変換してから、BigDecimal(String)コンストラクターを使用した場合と同じ結果は得られません。その結果を得るには、静的なvalueOf(double)メソッドを使用します

話の教訓:痛みは自傷行為のようです、ただ使用するnew BigDecimal(String val)か、BigDecimal.valueOf(double val)代わりに=)

于 2009-01-20T10:50:54.297 に答える
11

あなたの問題は、とは何の関係もありません。また、内部で2進分数を使用しているため、13.3を正確に表すことができないすべてのBigDecimalものがあります。Double

したがって、エラーは最初の行に表示されます。最初のBigDecimalものは単にそれを保存しますString.valueOf()が、2番目のものがほとんど運によって望ましい内容を持つようにするいくつかの魚のような丸めを行います。

于 2009-01-20T10:40:09.390 に答える
8

浮動小数点値がどのように実装されているか ( IEEE 754-1985 ) を知っておくとよいでしょう。そして突然、すべてが透明になります。

于 2009-01-20T10:39:12.993 に答える
5

これは のせいではありませんBigDecimal- のせいですdoubleの正確な値をBigDecimal正確に表しています。結果を小数点以下の数桁までしか表示していません。dString.valueOf

于 2009-01-20T10:38:07.460 に答える
3

2 進数型 ( doublefloat) で表される分数は、それらの型に正確に格納できません。

    Double d = 13.3;        
    BigDecimal bdNotOk = new BigDecimal(d);
    System.out.println("not ok: " + bdNotOk.toString());

    BigDecimal bdNotOk2 = new BigDecimal(13.3);
    System.out.println("not ok2: " + bdNotOk2.toString());

    double x = 13.3;
    BigDecimal ok = BigDecimal.valueOf(x);
    System.out.println("ok: " + ok.toString());

    double y = 13.3;
    // pretty lame, constructor's behavior is different from valueOf static method
    BigDecimal bdNotOk3 = new BigDecimal(y);
    System.out.println("not ok3: " + bdNotOk3.toString());

    BigDecimal ok2 = new BigDecimal("13.3");
    System.out.println("ok2: " + ok2.toString());

    Double e = 0.0;
    for(int i = 0; i < 10; ++i) e = e + 0.1; // some fractions cannot be accurately represented with binary
    System.out.println("not ok4: " + e.toString()); // should be 1


    BigDecimal notOk5 = BigDecimal.valueOf(e);
    System.out.println("not ok5: " + notOk5.toString()); // should be 1

    /* 
     * here are some fractions that can be represented exactly in binary:
     * 0.5   = 0.1   = 1 / 2
     * 0.25  = 0.01  = 1 / 4
     * 0.75  = 0.11  = 3 / 4
     * 0.125 = 0.001 = 1 / 8
     */

出力:

not ok: 13.300000000000000710542735760100185871124267578125
not ok2: 13.300000000000000710542735760100185871124267578125
ok: 13.3
not ok3: 13.300000000000000710542735760100185871124267578125
ok2: 13.3
not ok4: 0.9999999999999999
not ok5: 0.9999999999999999

BigDecimal.valueOf(d)またはを使用するだけnew BigDecimal(s)です。

于 2009-01-20T11:21:14.050 に答える