【问题标题】:I want to get the value with round but not getting proper result我想用 round 得到值但没有得到正确的结果
【发布时间】:2021-10-08 09:59:50
【问题描述】:

我想得到四舍五入的结果,请看附图。它有什么问题。

结果应该是:18.59

我使用了 float 而不是 double。

MRE:

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

观察到的输出:

18.58

【问题讨论】:

  • System.out.println((float)Math.round(18.585*100)/100);为我返回 18.59
  • 双倍值 = 18.585; System.out.println(((double)Math.round(value * 100))/100);打印 18,59........ 浮点值 = 18.585f; System.out.println(((double)Math.round(value * 100))/100);打印 18,58
  • @Petr F. 我使用了 float 而不是 double。
  • 使用 float 我得到相同的结果:double value = 18.585; System.out.println(((float)Math.round(value * 100))/100);打印 18,59........ 浮点值 = 18.585f; System.out.println(((float)Math.round(value * 100))/100);打印 18,58
  • 我投了反对票,因为您没有将代码粘贴为文本,也因为您没有给我们minimal reproducible example。很高兴你给了我们预期的结果。我们还需要观察到的结果。

标签: java android android-studio java-11


【解决方案1】:

问题

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

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

几种可能的解决方案

解决方案?有许多。我将介绍两个。

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

添加一个ε

让我们声明:

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

cmets 中建议您可以使用double 而不是floatdouble 具有更好的精度。其实float名声不好。 double 仍然不完全准确,因此虽然他们似乎解决了 18.585 的问题,但您可能会遇到其他值的相同问题。

链接

相关问题有很多好资料:Is floating point math broken?

【讨论】:

  • 我通过应用 BigDecimal 得到了解决方案。谢谢。
猜你喜欢
  • 2022-09-29
  • 1970-01-01
  • 2015-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-14
相关资源
最近更新 更多