java - 舍入操作需要幂等性

标签 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();
    }

最佳答案

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

无论哪种情况,主要问题是您在一个位置使用 double (并引入浮点不准确),而在另一个位置使用 BigDecimal (如果使用正确,受这些不准确的影响较小) )。

最简单的做法是将 double 设置为小数点后两位,然后按您喜欢的方式四舍五入。例如,所有这些值都满足您在评论中提到的所需条件。

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始终保持一致。没有真正的理由对原始 double 进行交错或交织和 BigDecimal,因为它只会导致这样的头痛。

关于java - 舍入操作需要幂等性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28291544/

相关文章:

java - 如何将 xml 配置 bean 转换为 Java 配置 bean?

java - 使用换行符的普遍接受的最佳实践

java - 为什么我的代码无法识别输入?

java - ThreadPoolExecutor 的终结器未完成,导致内存泄漏

java - 如何在 JtextArea 中选择和检索整行文本的字符串?

java - 如何更改滚动面板中按钮的大小

java - 如何在 ImageView 中显示捕获的图像?

java - 在 Spring Boot 应用程序中动态计划任务

java - 如何使用wiremock模拟服务

java - 在区域设置 'pl_PL' 的代码下未找到消息