2

最近、奇妙なJavaの2階の丸めについて質問し、代わりにBigDecimalsを使用するための回答を得たので、次のコードを試してみました。

BigDecimal velocity = new BigDecimal(-0.07);
BigDecimal afterMultiplyingBy200 = velocity.multiply( new BigDecimal(200.0) );
BigDecimal floored = afterMultiplyingBy200.setScale(0, RoundingMode.FLOOR);
System.out.println("After multiplication " + afterMultiplyingBy200);
System.out.println("floored value is " + floored);

そして、私は次の結果を得ています

After multiplication -14.000000000000001332267629550187848508358001708984375000
floored value is -15

BigDecimalを使用しても、-0.07に200を掛けた正しい値を取得できないようですが、正確に-14.0を取得するためにできることはありますか?

4

5 に答える 5

7

その質問に対する私の答えから:

コードがコンパイルまたは解釈されると、「0.1」はすでにその形式の最も近い数値に丸められているため、計算が行われる前でも小さな丸め誤差が発生します。

問題は、リテラルをnew BigDecimal(-0.07);使用して初期化するため、エラーが引き続き発生することです。代わりにa を取るコンストラクタを使用してください。doubleBigDecimalBigDecimalString

于 2012-05-15T14:54:30.217 に答える
5

double の使用による丸め誤差を避けるために、文字列コンストラクターを使用する必要があります。

BigDecimal velocity = new BigDecimal("-0.07");
BigDecimal afterMultiplyingBy200 = velocity.multiply(new BigDecimal("200"));

double を使用したコンストラクターの Javadoc 抽出- 強調鉱山:

  1. このコンストラクターの結果は、予測できない場合があります。Java で new BigDecimal(0.1) を記述すると、正確に 0.1 に等しい BigDecimal (スケール 1 のスケールなしの値 1) が作成されると思われるかもしれませんが、実際には 0.1000000000000000055511151231257827021181583404541015625 に等しくなります。これは、0.1 を double として正確に表現できないためです (さらに言えば、有限長の 2 進小数としても表現できません)。したがって、コンストラクターに渡される値は、見た目はともかく、0.1 と正確には等しくありません。
  2. 一方、String コンストラクターは完全に予測可能です。new BigDecimal("0.1") を書き込むと、予想どおり、0.1 に正確に等しい BigDecimal が作成されます。したがって、通常は、これよりも String コンストラクターを使用することをお勧めします。
于 2012-05-15T14:55:13.560 に答える
3

問題はここにあります:

BigDecimal velocity = new BigDecimal(-0.07);

-0.07として正確に表すことはできないため、コンストラクターdoubleに渡されるリテラル値は最終的に とはわずかに異なります。そのおおよその値を取得して実行するだけで、表示されている結果が生成されます。BigDecimal-0.07BigDecimal

試す:

BigDecimal velocity = new BigDecimal(-7, 2);
BigDecimal afterMultiplyingBy200 = velocity.multiply( new BigDecimal(2, -2) );
于 2012-05-15T14:54:12.117 に答える
0

特にRoundingModeを確認する必要がありますHALF_UP

于 2012-05-15T14:54:16.823 に答える