将BigDecimal舍入到最接近的5美分

Dón*_*nal 18 java rounding bigdecimal

我想弄清楚如何将货币金额向上舍入到最接近的5美分.以下显示了我的预期结果

1.03     => 1.05
1.051    => 1.10
1.05     => 1.05
1.900001 => 1.10
Run Code Online (Sandbox Code Playgroud)

我需要结果的精度为2(如上所示).

更新

按照下面的建议,我能做的最好的就是这个

    BigDecimal amount = new BigDecimal(990.49)

    // To round to the nearest .05, multiply by 20, round to the nearest integer, then divide by 20
   def result =  new BigDecimal(Math.ceil(amount.doubleValue() * 20) / 20)
   result.setScale(2, RoundingMode.HALF_UP)
Run Code Online (Sandbox Code Playgroud)

我不相信这是100%犹太人 - 我担心转换到双打时精度可能会丢失.然而,这是迄今为止我提出的最好的,似乎有效.

rob*_*nst 58

使用BigDecimal没有任何双打(改进了marcolopes的答案):

public static BigDecimal round(BigDecimal value, BigDecimal increment,
                               RoundingMode roundingMode) {
    if (increment.signum() == 0) {
        // 0 increment does not make much sense, but prevent division by 0
        return value;
    } else {
        BigDecimal divided = value.divide(increment, 0, roundingMode);
        BigDecimal result = divided.multiply(increment);
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

舍入模式例如是RoundingMode.HALF_UP.对于你的例子,你真的想要RoundingMode.UP(bd是一个只返回的助手new BigDecimal(input)):

assertEquals(bd("1.05"), round(bd("1.03"), bd("0.05"), RoundingMode.UP));
assertEquals(bd("1.10"), round(bd("1.051"), bd("0.05"), RoundingMode.UP));
assertEquals(bd("1.05"), round(bd("1.05"), bd("0.05"), RoundingMode.UP));
assertEquals(bd("1.95"), round(bd("1.900001"), bd("0.05"), RoundingMode.UP));
Run Code Online (Sandbox Code Playgroud)

另请注意,您的上一个示例中存在错误(将1.900001舍入到1.10).

  • 显然是最好的答案.请upvote,因为它的排名高于那些使用浮点的hacky解决方案. (7认同)
  • 它们并不是字面上的hacky,但它们只适用于小到足以放入double的BigDecimals。因此,它们不是可靠的解决方案。这个适用于任何 BigDecimal。 (2认同)

Jam*_*nen 11

我会尝试乘以20,舍入到最接近的整数,然后除以20.这是一个黑客,但应该得到正确的答案.


mar*_*pes 8

我几年前用Java写过这个:https://github.com/marcolopes/dma/blob/master/org.dma.java/src/org/dma/java/math/BusinessRules.java

/**
 * Rounds the number to the nearest<br>
 * Numbers can be with or without decimals<br>
 */
public static BigDecimal round(BigDecimal value, BigDecimal rounding, RoundingMode roundingMode){

    return rounding.signum()==0 ? value :
        (value.divide(rounding,0,roundingMode)).multiply(rounding);

}


/**
 * Rounds the number to the nearest<br>
 * Numbers can be with or without decimals<br>
 * Example: 5, 10 = 10
 *<p>
 * HALF_UP<br>
 * Rounding mode to round towards "nearest neighbor" unless
 * both neighbors are equidistant, in which case round up.
 * Behaves as for RoundingMode.UP if the discarded fraction is >= 0.5;
 * otherwise, behaves as for RoundingMode.DOWN.
 * Note that this is the rounding mode commonly taught at school.
 */
public static BigDecimal roundUp(BigDecimal value, BigDecimal rounding){

    return round(value, rounding, RoundingMode.HALF_UP);

}


/**
 * Rounds the number to the nearest<br>
 * Numbers can be with or without decimals<br>
 * Example: 5, 10 = 0
 *<p>
 * HALF_DOWN<br>
 * Rounding mode to round towards "nearest neighbor" unless
 * both neighbors are equidistant, in which case round down.
 * Behaves as for RoundingMode.UP if the discarded fraction is > 0.5;
 * otherwise, behaves as for RoundingMode.DOWN.
 */
public static BigDecimal roundDown(BigDecimal value, BigDecimal rounding){

    return round(value, rounding, RoundingMode.HALF_DOWN);

}
Run Code Online (Sandbox Code Playgroud)


Pet*_*rey -3

您可以使用普通 double 来执行此操作。

double amount = 990.49;
double rounded = ((double) (long) (amount * 20 + 0.5)) / 20;
Run Code Online (Sandbox Code Playgroud)

编辑:对于负数,您需要减去 0.5

  • http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html “如上所述,这种数据类型 [double] 不应该用于精确值,例如货币。” (9认同)
  • @PeterLawrey 感谢您的回复,但您仍然给了我们相当模糊、手足无措的答案。网上有很多关于在货币等精度至关重要的情况下使用浮点数的危险的参考文献。请您仅指出一个参考文献(最好是一个信誉良好的参考文献)来支持您的主张,即浮点(或至少双精度)适合财务计算。 (3认同)
  • @PeterLawrey“我是”——我们知道为什么是过去时态;)开个玩笑:不,这是一个非常精心设计的黑客行为。如果我们谈论的是同一事件。但就我心目中的情况而言,这不是一家银行,而是几家银行。所以也许这是另一个:) (2认同)