我想获得 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。)
几个可能的解决方案
解决办法?有许多。我会介绍两个。
- 在四舍五入前为您的值添加一个小值(有时称为 epsilon)。
- 使用
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
而不是 float
。 double
具有更好的精度。其实float
名声不好。 double
仍然不完全精确,因此虽然他们似乎解决了 18.585 的问题,但您冒着 运行 进入其他值的相同问题的风险。
Link
有很多有用信息的相关问题:Is floating point math broken?
我想得到四舍五入的结果,请看附图。怎么了。
结果应该是: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。)
几个可能的解决方案
解决办法?有许多。我会介绍两个。
- 在四舍五入前为您的值添加一个小值(有时称为 epsilon)。
- 使用
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
而不是 float
。 double
具有更好的精度。其实float
名声不好。 double
仍然不完全精确,因此虽然他们似乎解决了 18.585 的问题,但您冒着 运行 进入其他值的相同问题的风险。
Link
有很多有用信息的相关问题:Is floating point math broken?