如何使用 BigDecimal 而不是 double 在 Java 中实现 Excel MROUND() 函数

How to implement Excel MROUND() function in Java using BigDecimal instead of double

提问人:sameer59 提问时间:10/4/2023 最后编辑:sameer59 更新时间:10/4/2023 访问量:81

问:

如何在 Java 中四舍五入到特定的倍数?在excel中,有mround函数,它允许轻松舍入到指定的倍数,如下所示:

mRound(variable,multiple)

例如,这就是 Java 函数在给定的“数字”和“因子”下应该如何工作。 要获得更多测试数据,只需在 MS Excel 中的“数字”和“因子”列下方添加,然后在下一列中使用 excel 内置的 MROUND 函数作为 =MROUND(Number, Factor)

enter image description here

我知道如何使用 double 来完成它,但是当我处理财务数据时,我需要一个 BigDecimal 的解决方案

双 -

double mRound(double value, double factor) {
    return Math.round(value / factor) * factor;
}

这就是excel MROUND函数的工作原理 -MROUND Excel 函数将数字四舍五入到所提供数字的最接近的倍数。您必须考虑 Excel 如何知道是向上舍入还是向下舍入。这取决于划分的结果。

例如 16 / 3 = 5.33333,这里的十进制值小于 0.5,因此数字 3 的最接近倍数的结果是 5,因此 3 * 5 = 15。在这里,如果十进制值小于 0.5,Excel 会向下舍入该值。

同样,看看这个等式 20 / 3 = 6.66667。在此等式中,十进制值大于 0.5,因此 Excel 将结果四舍五入为 7,因此 3 * 7 = 21。

有关 MROUND 工作原理的更多详细信息,请参阅 - https://www.wallstreetmojo.com/mround-in-excel/

Java 数学 数字 四舍五入 大十进制

评论

0赞 sameer59 10/4/2023
我尝试使用divide()。round()、multiply(),但它们并没有像预期的那样提供帮助。这就是 MROUND 函数在 excel 中的工作方式 wallstreetmojo.com/mround-in-excel
1赞 sameer59 10/4/2023
道歉。我在问题中添加了更多细节。如果我们更改因子值,则上述@user85421解不起作用。
0赞 sameer59 10/4/2023
我真的不确定。但是,如果您在 MS excel 中使用高于“数字”和“因子”列值并使用 excel 的 MROUND 函数,您将获得上述结果。例如 MROUND(532.785, 0.01) = 532.78

答:

1赞 4 revsuser85421 #1

该类提供了所有需要的方法来执行相同的操作 - 舍入有点棘手,因为使用需要精度:总位数,而不是小数部分的位数。但可以替代 .BigDecimalMath.round(value / factor) * factor;BigDecimal#roundMathContextBigDecimal#setScaleMath#round

假设两者都已经存在,我们将你的方法写成:valuesfactorBigDecimal

static BigDecimal mRound(BigDecimal value, BigDecimal factor) {
    return 
        value
        .divide(factor)
        .setScale(0, RoundingMode.HALF_UP)
        .multiply(factor);
}

我相信 和 方法不需要更多解释,有关详细信息,请参阅 javadoc 的 。divde()multiply()BigDecimal

这些方法用于对数字进行舍入。如上所述:“刻度是小数点右边的位数。
我们使用了:
setScale()

  • scale: 0因为我们不需要十进制数字;
  • roundingMode: HALF_UP由于我们想要或更大范围再次四舍五
    入,请参阅不同模式的文档
    0.5

若要从结果中删除尾随零,请在乘法后使用以下方法:stripTrailingZeros()

return 
    ...
    .multiply(factor)
    .stripTrailingZeros();

请注意,使用可能会导致问题,因为这不是一个确切的表示 - 请改用!
例如,结果为 .
new BigDecimal(double)doublenew BigDecimal(String)new BigDecimal(1.2)1.1999999999999999555910790149937383830547332763671875


测试

List<List<BigDecimal>> data = """
    523.235  0.05
    523.265  0.05
    523.205  0.05
    523.735  0.05
    523.785  0.05
    523.75   0.05
    523.705  0.05
    15       8
    17       5
    523.235  0.01
    523.265  0.01
    523.205  0.01
    523.735  0.01
    523.785  0.01
    523.75   0.01
    523.705  0.01
    """
.lines()
.map(line -> Arrays.stream(line.split("\\h+")).map(BigDecimal::new).toList())
.toList();
for (var test : data) {
    var value = test.get(0);
    var factor = test.get(1);
    var result = mRound(value, factor);
    System.out.printf("%10s  %5s  %10s%n", value, factor, result);
}

结果

   523.235   0.05      523.25
   523.265   0.05      523.25
   523.205   0.05      523.20
   523.735   0.05      523.75
   523.785   0.05      523.80
    523.75   0.05      523.75
   523.705   0.05      523.70
        15      8          16
        17      5          15
   523.235   0.01      523.24
   523.265   0.01      523.27
   523.205   0.01      523.21
   523.735   0.01      523.74
   523.785   0.01      523.79
    523.75   0.01      523.75
   523.705   0.01      523.71

请注意,结果与给定的输入图像不匹配 - 我想知道这是否是 Excel 中的错误(它是否使用 ?523.785 0.01double