Java,BigDecimal。除法问题

16

我正在尝试计算一个百分比“因子”。也就是说,给定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

我做错了什么?如何正确地将两个大的十进制数相除?

顺便说一下,我正在使用BigDecimal,因为我将计算货币百分比,所以我想在舍入方面有控制。

4个回答

17

我认为最好的解决方法是在除法时设置所需的比例: 在这种情况下可能是2。

    var hundred = new BigDecimal(100);
    var percentage = new BigDecimal(20);
    var value = new BigDecimal(500);
    
    var percentageFactor = 
        percentage.divide(hundred,2, BigDecimal.ROUND_HALF_UP);
    
    value = value.multiply(percentageFactor);
    System.out.println("final value:"+ value);

最终值:100.00

乘法使用因数(0+2)的标度,但也可以指定。

我会在舍入模式上使用ROUND_HALF_UP进行会计(依据我的立法)或ROUND_EVEN(用于统计学)。


9
new BigDecimal("20")的规模为零,因为里面没有小数点。这意味着你的percentage.divide(hundred, BigDecimal.ROUND_FLOOR)将产生零(它实际上是int(20/100)或者0)。
如果你真的想要做分数运算,使用new BigDecimal("20.00")以便正确设置度量,或者使用其他构造函数来明确设置度量。
下面是将20更改为20.00后的输出,包括您的拼写错误 :-)
factor:0.20
final falue:100.00
Float Value:100.0

0

你的代码中,factor 的值为0而不是0.2的原因是:

  1. 你将 RoundingMode 设置为 FLOOR(即向下取整),并且
  2. 你的 percentage 变量具有隐式的小数位数为0(任何未指定小数位数的四舍五入数字的 BigDecimal 将具有小数位数为0)

因此,当你调用 divide 方法时,你会将任何小数向下舍入,并保持小数位数为0,因此0.2被舍入为0。

要获取正确的数字,你可以:

  1. 显式地指定小数位数,或者
  2. 由于你知道你正在除以100,所以可以直接使用 BigDecimal#divide(BigDecimal) 方法(不提供小数位数或 RoundingMethod)。在你的情况下,该方法不会抛出 ArithmeticException,因为不存在非终止小数的可能性(例如 20 / 100 = 0.2,20 / 10000 = 0.002 - 当除以100时,小数总是终止的)。

但是,如果你要除以另一个数字,比如3,那么你需要指定精度,因为存在无限循环小数的可能性(想一想 10/3=3.3333333333...)


0

float类型只有6位有效数字,几乎从来不是一个好的选择,我建议您使用double类型代替。(在某些情况下,BigDecimal类型可能更好)


如果你想要对舍入有更好的控制,你就不应该使用浮点数,无论是float还是double。最好使用BigDecimal。 - markusk
通常只有最终结果需要进行控制舍入,因此您仅使用BigDecimal来舍入结果(或简单的辅助方法)。这可以显着地更加简单和快速。 - Peter Lawrey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接