職場で、大きな数値を1000で除算しようとしたときに問題が見つかりました。この数値はデータベースに由来します。
この方法があるとしましょう:
private static BigDecimal divideBy1000(BigDecimal dividendo) {
if (dividendo == null) return null;
return dividendo.divide(BigDecimal.valueOf(1000), RoundingMode.HALF_UP);
}
次の電話をかけるとき
divideBy1000(new BigDecimal("176100000"))
176100の期待値を受け取ります。しかし、以下の行を試してみると
divideBy1000(new BigDecimal("1761e+5"))
値200000を受け取ります。これはなぜ発生しますか?両方の数字は異なる表現で同じであり、最新のものはデータベースから受け取ったものです。どういうわけか、JVMは数1761を1000で割って、端数を切り上げて0で埋めていることを理解しています。
この種の動作を回避する最良の方法は何ですか?元の番号は私によって管理されていないことに注意してください。
Javadocで指定されているように、BigDecimal
は整数値とscaleで定義されます。
したがって、BigDecimalで表される数値の値は(unscaledValue×10 ^(-scale))です。
したがって、BigDecimal("1761e+5")
のスケールは-5で、BigDecimal(176100000)
のスケールは0です。
2つのBigDecimal
の除算は、除算時にスケールが指定されていないため、-5スケールと0スケールを使用して行われます。 divide
documentation は、結果が異なる理由を説明しています。
divide
_public BigDecimal divide(BigDecimal divisor)
_
BigDecimal
を返します。値は_(this / divisor)
_で、優先スケールは_(this.scale() - divisor.scale())
_;です。正確な商を表現できない場合(終了しない10進数の展開があるため)、ArithmeticException
がスローされます。パラメータ:
divisor
-このBigDecimalを分割する値。戻り値:
_this / divisor
_スロー:
ArithmeticException
—正確な商に終端の10進数展開がない場合以来:
1.5
分割時にスケールを指定した場合、例えばdividendo.divide(BigDecimal.valueOf(1000), 0, RoundingMode.HALF_UP)
同じ結果が得られます。
式new BigDecimal("176100000")
およびnew BigDecimal("1761e+5")
は、等しくないです。 BigDecimal
は、値と精度の両方を追跡します。
BigDecimal("176100000")
の精度は9桁で、内部的にはBigInteger("176100000")
として表され、1倍されます。BigDecimal("1761e+5")
は4桁の精度であり、内部的にはBigInteger("1761")
、100000倍。
BigDecimal
を値で除算すると、結果は精度の桁を尊重し、一見等しい値に対して異なる出力をもたらします。
bigDecimalであなたの部門に。
dividendo.divide(divisor,2,RoundingMode.CEILING)//00.00 nothing for up and nothing for down
この操作では、小数点以下2桁の精度があります。
ええ、それはあなたが実験している問題の一種です。私がそうするかもしれないならば、あなたが指数数だけを持っている状況で、あなたはそれらを投げて、そしてあなたの方法を使うべきです。私が提案するのは、このコードのほんの一部です。
long longValue = Double.valueOf("1761e+5").longValue();
BigDecimal value= new BigDecimal(longValue);
これらの文字列を新しいBigDecimalに変換し、このBigDecimal値を返すメソッドで使用します。その後、divideBy1000でこれらの返された値を使用できます。これにより、発生している問題がすべて解決されます。
それらがたくさんある場合は、リストのようなデータ構造にそれらのBigDecimalを保存することでもできます。次に、foreachループを使用します。このループでは、divideBy1000を適用すると、新しい値がそれぞれ別のリストに保存されます。次に、このリストにアクセスして、新しい値のセットを取得する必要があります。
それが役に立てば幸い :)
BigDecimalに10の累乗を掛けるときはいつでも、この場合は10を掛けます-3、dividendo.scaleByPowerOfTen(power)
を使用して、BigDecimalオブジェクトのスケールのみを変更し、丸めの問題をサイドステップするか、少なくとも後の計算に移動することができます。
ここでの他の回答は、任意の数で割るより一般的なケースをカバーしています。
round()
を使用してみてください。
_private static BigDecimal divideBy1000(BigDecimal dividendo) {
if (dividendo == null) return null;
return dividendo.divide(BigDecimal.valueOf(1000)).round(new MathContext(4, RoundingMode.HALF_UP));
}
public static void main(String []args){
BigDecimal bigD = new BigDecimal("1761e5");
BigDecimal bigDr = divideBy1000(bigD);
System.out.println(bigDr);
}
_
new MathContext(4, RoundingMode.HALF_UP))
行は、除算を4桁に戻します。
これにより、以下が生成されます。
_1.761E+5
_
これはあなたが望むものです。 (: