在 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/