15

次の動作が古い問題であることは知っていますが、まだ理解できません。

System.out.println(0.1 + 0.1 + 0.1);    

または、使用しているにもかかわらずBigDecimal

System.out.println(new BigDecimal(0.1).doubleValue()
    + new BigDecimal(0.1).doubleValue()
    + new BigDecimal(0.1).doubleValue());

この結果が:0.30000000000000004ではなく: である理由は0.3?

どうすればこれを解決できますか?

4

5 に答える 5

31

あなたが実際に望んでいるのは

new BigDecimal("0.1")
 .add(new BigDecimal("0.1"))
 .add(new BigDecimal("0.1"));

コンストラクターはのnew BigDecimal(double)すべての不正確さを取得するdoubleため、 と言った時点で0.1、丸め誤差が既に導入されています。Stringコンストラクターを使用すると、 double.

于 2012-03-20T22:07:17.140 に答える
9

まず決して、BigDecimal の double コンストラクターを使用しないでください。いくつかの状況では正しいことかもしれませんが、ほとんどの場合はそうではありません

入力を制御できる場合は、既に提案されている BigDecimal String コンストラクターを使用します。そうすれば、あなたが望むものを正確に得ることができます。すでに double がある場合 (結局発生する可能性があります)、double コンストラクターを使用しないで、代わりに静的valueOfメソッドを使用してください。これには、少なくとも問題を軽減する double の正規表現が得られるという優れた利点があり、結果は通常、はるかに直感的です。

于 2012-03-20T23:39:12.803 に答える
4

これは Java の問題ではなく、コンピュータ全般の問題です。中心的な問題は、10 進数形式 (人間の形式) から 2 進数形式 (コンピューター形式) への変換にあります。10 進数形式の一部の数値は、無限に繰り返される 10 進数がなければ、2 進数形式では表現できません。

たとえば、10 進数の 0.3 は 0.01001100... 2 進数ですが、コンピューターには数値を保存するための「スロット」(ビット) が限られているため、無限表現全体をすべて保存することはできません。0.01001100110011001100 のみを保存します (たとえば)。しかし、その 10 進数は 0.3 ではなく、代わりに 0.30000000000000004 になります。

于 2012-03-20T21:45:53.747 に答える
3

これを試して:

BigDecimal sum = new BigDecimal(0.1).add(new BigDecimal(0.1)).add(new BigDecimal(0.1));

編集: 実際、Javadoc を調べると、これにはオリジナルと同じ問題があります。コンストラクターBigDecimal(double)は、正確に 0.1 と等しくない 0.1 の正確な浮動小数点表現に対応する BigDecimal を作成します。

ただし、整数は常に浮動小数点表現で正確に表現できるため、これにより正確な結果が得られます。

BigDecimal one = new BigDecimal(1);
BigDecimal oneTenth = one.divide(new BigDecimal(10));

BigDecimal sum = oneTenth.add(oneTenth).add(oneTenth);
于 2012-03-20T21:41:22.453 に答える
3

あなたが抱えている問題は、0.1がわずかに高い数値で表されることです。

System.out.println(new BigDecimal(0.1));

版画

0.1000000000000000055511151231257827021181583404541015625

Double.toString() はこの表現エラーを考慮しているため、表示されません。

同様に、0.3 は実際よりもわずかに低い値で表されます。

0.299999999999999988897769753748434595763683319091796875

0.1 の表示値に 3 を掛けると、0.3 の表示値は得られず、代わりに少し高い値が得られます。

0.3000000000000000166533453693773481063544750213623046875

これは単なる表現誤差ではなく、演算による丸め誤差でもあります。これは、Double.toString() が修正できる範囲を超えているため、丸めエラーが表示されます。

ストーリーの教訓は、ソリューションを適切に使用するfloatdouble、丸めることもできます。

double d = 0.1 + 0.1 + 0.1;
System.out.println(d);
double d2 = (long)(d * 1e6 + 0.5) / 1e6; // round to 6 decimal places.
System.out.println(d2);

版画

0.30000000000000004
0.3
于 2012-03-21T09:15:07.677 に答える