0

In java code I have 1 input being :16275.874999999998

I build a method which rounds it up to: 16275.87

But the right answer is: 16275.88

How do I fix that in Java?

My current rounding method:

public static double round(final double value, final int places) {
    if (places < 0) throw new IllegalArgumentException();

    BigDecimal bd = BigDecimal.valueOf(value);
    bd = bd.setScale(places, RoundingMode.HALF_UP);
    return bd.doubleValue();
}

Edit: I thought "the right answer" had .88 because the 9s would round up but that's not the case with the method I am using, will definitely look into rewrite it to consider previous decimal points.

Many thanks for the replies everyone!

  • 2
    How is rounding `16275.874999999998` to `16275.88` the correct answer if you're using the rounding mode HALF_UP? If you round to 2 places then `.874xxx` will be rounded to `.87` not matter the `xxx` part - it's in the lower half of the range. – Thomas Jul 02 '19 at 15:24
  • 2
    "But the right answer is: 16275.88" <- no, rounding does not work that way. Your number is closer to 16275.87 and therefor gets correctly rounded to that value – OH GOD SPIDERS Jul 02 '19 at 15:24
  • If 16275.874999999998 is the imprecise result of a calculation, and should have been 16275.875, i.e. it is off by one [ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place), then do the calculation using `BigDecimal`, not `double`. See [Is floating point math broken?](https://stackoverflow.com/q/588004/5221149) – Andreas Jul 02 '19 at 15:33
  • In maths, when you are rounding a number you start from the end of it. This method obviously doesn't and I thought it did. My fault for not checking the documentation. – Harris Mavrokefalidis Jul 03 '19 at 10:15

2 Answers2

1

Java is actually rounding your number correctly. Since you're rounding to 2 places, the setScale method looks at the third decimal spot which is 4 in your example. Since 4 < 5, your HALF_UP rounding mode will behave like ROUND_DOWN, which is why your output is 16275.87 instead of 16275.88

In order for your number to round up to 16275.88, you would need to run your method with input as round(round(16275.874999999998, 3), 2)

1

If you are looking to always round up then you need to use RoundingMode.CEILING or RoundingMode.UP (depending on how you want negative numbers to behave), instead of RoundingMode.HALF_UP

    bd = bd.setScale(places, RoundingMode.CEILING);

HALF_UP will round up for anything with 5 or over in the first decimal place that is getting discarded and round down for anything less than 5 in that position.

CEILING and UP will always round up for positive numbers so 16275.871 will round to 16275.88. The difference between the two is how they handle negative numbers. CEILING rounds towards the positive numbers and UP will round towards the larger negative number.

CEILING of -16275.871 = -16275.871
UP of -16275.871 = -16275.88
Marc G. Smith
  • 876
  • 6
  • 8