I want to get the result with round the value please see the attached image. What is wrong with it.
The result should be : 18.59
I have used float instead of double.
MRE:
float value = 18.585f; System.out.println(((float)Math.round(value * 100))/100);
Observed output:
18.58
Advertisement
Answer
The problem
The problem is not in the rounding. The problem is in the value that you are rounding. You think the value is 18.585. It is not. float
values are not precise. The real value in your float
variable is somewhere around 18.584999 because a float
hasn’t got a better precision. The correct rounding of this value to two decimal places is 18.58. The result you got.
(Except you got 18.5799999237060546875 because the new value isn’t precise either; but in printed as 18.58.)
A couple of possible solutions
The solution? There are many. I will present two.
- Add a small value (sometimes referred to as an epsilon) to your value before rounding.
- Use
BigDecimal
instead offloat
.
Add an epsilon
Let’s declare:
private static final float EPSILON = 0.000_001f;
And use it:
float value = 18.585f; System.out.println(((float) Math.round((value + EPSILON) * 100)) / 100);
Output is the desired:
18.59
For values not ending in 5
adding the epsilon will not make any change to the rounded value, so only in weird corner cases does this approach risk giving undesired results.
Use BigDecimal
A BigDecimal
holds the full precision of a decimal number no matter how many decimals you give it.
BigDecimal value = new BigDecimal("18.585"); BigDecimal roundedValue = value.setScale(2, RoundingMode.HALF_UP); System.out.println(roundedValue);
18.59
I am specifying RoundingMode.HALF_UP
to make sure that rounding of 18.585 goes up to 18.59, not down to 18.58.
It’s crucial to use the constructor that takes a String
argument so we also pass the full precision of your number into the BigDecimal
. If we just passed the float
to the BigDecimal
, the imprecision would go along. Just to deter you, see how this fails:
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
It was suggested in the comments that you could use double
instead of float
. double
has a much better precision. Actually float
has got a bad reputation. double
still isn’t fully precise, so while they seem to fix the problem with 18.585, you risk running into the same problem with some other value.
Link
Related question with a lot of good information: Is floating point math broken?