需要幂等于舍入操作

时间:2015-02-03 04:46:43

标签: java

在Java中,我希望0.101d,0.109999999d和0.11000d在功能上都相同。我试图使用BigDecimal和一个具有2位精度的MathContext和RoundingMode.CEILING来做到这一点,但我的单位测试显示0.11000轮到0.12。我希望0.110000d回合到0.11。

    private static MathContext targetMathContext = new MathContext(2, RoundingMode.CEILING);

public static double roundedTarget(double d) {
    BigDecimal bd = new BigDecimal(d,targetMathContext);
    return bd.doubleValue();
}

JUnit:

    double c = 0.445d;
    double s = 0.5d;
    double p = (s-c)/s; // 0.1099999..... in dfp
    double rgpp = roundedTarget(p); // 0.11
    double rgppp = roundedTarget(rgpp); // 0.12
    // operation is not idempotent as f(x) != f(f(x))   :(

    Assert.assertEquals("These values should be equal",rgpp,rgppp);

解决方案:

    public static double roundedTarget(double d) {
        return  BigDecimal.valueOf(d)
                  .setScale(2,BigDecimal.ROUND_CEILING)
                  .doubleValue();
    }

1 个答案:

答案 0 :(得分:2)

我不愿意将此操作称为幂等,因为您的第一个函数应用程序的输入将与下一个不同(因为您获得的结果将更改x的值)。 / p>

在任何一种情况下,主要问题是您在一个地方使用双打(并引入浮点不准确),而在另一个地方使用BigDecimal(如果使用正确,则受这些不准确性的影响较小)

最简单要做的事情是在你的双打上设置2个小数位的比例,然后根据你喜欢的方式对它们进行舍入。例如,所有这些值都满足您在评论中提到的条件。

BigDecimal firstDecimal = BigDecimal.valueOf(0.101).setScale(2, RoundingMode.CEILING);
BigDecimal secondDecimal = BigDecimal.valueOf(0.10999).setScale(2, RoundingMode.CEILING);
BigDecimal thirdDecimal = BigDecimal.valueOf(0.110000).setScale(2, RoundingMode.CEILING);
BigDecimal fourthDecimal = BigDecimal.valueOf(0.1101).setScale(2, RoundingMode.CEILING);

System.out.println(firstDecimal); // 0.11
System.out.println(secondDecimal); // 0.11
System.out.println(thirdDecimal); // 0.11
System.out.println(fourthDecimal); // 0.12

这里的主要内容是:如果您要使用BigDecimal始终与之保持一致。没有真正的理由进行交织或交织工作使用原始双打和BigDecimal,因为它只会导致像这样的头痛。