我想获得 round 的价值但没有得到正确的结果

I want to get the value with round but not getting proper result

我想得到四舍五入的结果,请看附图。怎么了。

结果应该是:18.59

我用了 float 而不是 double。

MRE:

    float value = 18.585f;
    System.out.println(((float)Math.round(value * 100))/100);

观察到的输出:

18.58

问题

问题不在于四舍五入。问题在于您舍入的值。您认为该值为 18.585。它不是。 float 值不精确。 float 变量的实际值在 18.584999 左右,因为 float 没有更好的精度。此值的正确四舍五入为小数点后两位是 18.58。你得到的结果。

(除了你得到 18.5799999237060546875 因为新值也不精确;但打印为 18.58。)

几个可能的解决方案

解决办法?有许多。我会介绍两个。

  1. 在四舍五入前为您的值添加一个小值(有时称为 epsilon)。
  2. 使用 BigDecimal 而不是 float

添加一个 epsilon

让我们声明:

private static final float EPSILON = 0.000_001f;

并使用它:

    float value = 18.585f;
    System.out.println(((float) Math.round((value + EPSILON) * 100)) / 100);

输出是期望的:

18.59

对于不以 5 结尾的值,添加 epsilon 不会对四舍五入的值进行任何更改,因此只有在奇怪的极端情况下,这种方法才会有产生不良结果的风险。

使用 BigDecimal

一个 BigDecimal 保持十进制数的完整精度,无论你给它多少位小数。

    BigDecimal value = new BigDecimal("18.585");
    BigDecimal roundedValue = value.setScale(2, RoundingMode.HALF_UP);
    System.out.println(roundedValue);
18.59

我指定 RoundingMode.HALF_UP 以确保 18.585 的四舍五入上升到 18.59,而不是下降到 18.58。

使用带有 String 参数的构造函数至关重要,因此我们还将您的数字的完整精度传递给 BigDecimal。如果我们只是将 float 传递给 BigDecimal,那么不精确就会随之而来。只是为了阻止你,看看这是怎么失败的:

    BigDecimal value = new BigDecimal(18.585f);
    System.out.println(value);
    BigDecimal roundedValue = value.setScale(2, RoundingMode.HALF_UP);
    System.out.println(roundedValue);
18.58499908447265625
18.58

评论中建议您可以使用 double 而不是 floatdouble 具有更好的精度。其实float名声不好。 double 仍然不完全精确,因此虽然他们似乎解决了 18.585 的问题,但您冒着 运行 进入其他值的相同问题的风险。

Link

有很多有用信息的相关问题:Is floating point math broken?