web-dev-qa-db-ja.com

Java、BigDecimal。除算の問題

パーセンテージの「係数」を計算しようとしています。つまり、20%が与えられた場合、それを0.2に変換します(私の意図は、後で値にそれを掛けて、値の20%を取得することです)。

とにかく、質問はこのコードに関連しています:

_public static void main(String[] args) {
    int roundingMode = BigDecimal.ROUND_FLOOR;
    BigDecimal hundred = new BigDecimal("100");
    BigDecimal percentageFactor = null;
    BigDecimal percentage = new BigDecimal("20");
    BigDecimal value = new BigDecimal("500");
    percentageFactor = percentage.divide(hundred, roundingMode);
    float f = percentage.floatValue() / hundred.floatValue();
    f = value.floatValue() * f;
    BigDecimal aux = value.multiply(percentageFactor);
    System.out.println("factor:"+percentageFactor.toString());
    System.out.println("final falue:"+aux.toString());
    System.out.println("Float Value:"+f);       
}
_

この結果は次のようになると思います。

_factor: 0.2
final value: 100
float value: 100
_

しかし、代わりにpercentage.divide(hundred, roundingMode);がゼロを返しているので、次のようになります。

_factor:0
final falue:0
Float Value:100.0
_

私は何が間違っているのですか? 2つの大きな小数を正しく分割するにはどうすればよいですか?

ちなみに、パーセンテージを計算するのでBigDecimalを使用しているので、丸めを制御したいと思います。

14
gonso

最善の解決策は、分割するときに要求されたスケールを設定することだと思います。この場合はおそらく2です。

    BigDecimal hundred = new BigDecimal(100);
    BigDecimal percentage = new BigDecimal(20);
    BigDecimal value = new BigDecimal(500);
    BigDecimal percentageFactor =
                 percentage.divide(hundred,2, BigDecimal.ROUND_HALF_UP);

    value = value.multiply(percentageFactor);
    System.out.println("final value:"+ value);

最終値100.00

(乗算は因数(0 + 2)のスケールを使用していますが、指定することもできます。)

アカウンティング(私の法律では)にはHALF_UPを使用し、丸めモードではEVEN(統計用)を使用します。

14
KarlP

new BigDecimal("20")のスケールは、小数点がないためゼロです。つまり、percentage.divide(hundred, BigDecimal.ROUND_FLOOR)はゼロを生成します(事実上int(20/100)または_0_です)。

分数の処理を本当に実行したい場合は、new BigDecimal("20.00")を使用してスケールが正しく設定されるか、他のコンストラクターの1つを使用してスケールを具体的に設定します。

_20_から_20.00_への単純な変更からの出力は次のとおりです。

_factor:0.20
final falue:100.00
Float Value:100.0
_
9
paxdiablo

floatの精度はわずか6桁であり、決して良い選択ではありません。代わりにdoubleを使用することをお勧めします。 (またはBigDecimalの方が良い場合もあります)

0
Peter Lawrey

コードでfactorが0.2ではなく0である理由は、

  1. roundingModeをFLOOR(つまり、ROUND DOWN)に設定し、
  2. percentage変数の暗黙のスケールは0です(スケールを指定せずに丸め番号から初期化されたBigDecimalsのスケールは0になります)

したがって、divideを呼び出すと、小数が切り捨てられ、スケールが0に維持されるため、0.2は0に切り捨てられます。

正しい番号を取得するには、次のいずれかを行うことができます

  1. スケールを明示的に指定するか、
  2. 100で除算していることがわかっているので、代わりにBigDecimal#divide(BigDecimal)メソッドを使用できます(scaleまたはRoundingMethodを提供しません)。あなたの場合、小数が終了しない可能性がないため、メソッドはArithmeticExceptionをスローしません(20/100 = 0.2、20/10000 = 0.002-小数は常に100で割ると終了します)。

ただし、3などの別の数値で除算する場合は、小数点以下が終了しない可能性があるため、スケールを指定する必要があります(10/3 = 3.3333333333 ...と考えてください)。

0
HongYi