Skip to content
Advertisement

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

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

round problem

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.

  1. Add a small value (sometimes referred to as an epsilon) to your value before rounding.
  2. Use BigDecimal instead of float.

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?

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement