NumberFormat rounding issue with Java 8 only

java, java-8

Solution

I could track down this issue to class `java.text.DigitList` line 522.

The situation is that it thinks the decimal digits `6.0289` are already rounded (which is correct when comparing to the equivalent `BigDecimal` representation `6.208899…`) and decides to not round up again. The problem is that this decision makes sense only in the case that the digit resulting from rounding up is `5`, not when it is bigger than `5`. Note how the code for `HALF_DOWN` correctly differentiates between the `digit=='5'` and `digit>'5'` case.

This is a bug, obviously, and a strange one given the fact that the code for doing similar right (just for the other direction) is right below the broken one.

        case HALF_UP:
            if (digits[maximumDigits] >= '5') {
                // We should not round up if the rounding digits position is
                // exactly the last index and if digits were already rounded.
                if ((maximumDigits == (count - 1)) &&
                    (alreadyRounded))
                    return false;

                // Value was exactly at or was above tie. We must round up.
                return true;
            }
            break;
        case HALF_DOWN:
            if (digits[maximumDigits] > '5') {
                return true;
            } else if (digits[maximumDigits] == '5' ) {
                if (maximumDigits == (count - 1)) {
                    // The rounding position is exactly the last index.
                    if (allDecimalDigits || alreadyRounded)
                        /* FloatingDecimal rounded up (value was below tie),
                         * or provided the exact list of digits (value was
                         * an exact tie). We should not round up, following
                         * the HALF_DOWN rounding rule.
                         */
                        return false;
                    else
                        // Value was above the tie, we must round up.
                        return true;
                }

                // We must round up if it gives a non null digit after '5'.
                for (int i=maximumDigits+1; i<count; ++i) {
                    if (digits[i] != '0') {
                        return true;
                    }
                }
            }
            break;

The reason why this doesn’t happen to the other number is that `6.2088` is not the result of rounding up (again, compare to the `BigDecimal` output `6.208800…`). So in this case it will round up.

Problem

Can somebody explain to me why the following code: ``` public class Test { public static void main(String... args) { round(6.2088, 3); round(6.2089, 3); } private static void round(Double num, int numDecimal) { System.out.println("BigDecimal: " + new BigDecimal(num).toString()); // Use Locale.ENGLISH for '.' as decimal separator NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH); nf.setGroupingUsed(false); nf.setMaximumFractionDigits(numDecimal); nf.setRoundingMode(RoundingMode.HALF_UP); if(Math.abs(num) - Math.abs(num.intValue()) != 0){ nf.setMinimumFractionDigits(numDecimal); } System.out.println("Formatted: " + nf.format(num)); } } ``` gives the following output? ``` [me@localhost trunk]$ java Test BigDecimal: 6.208800000000000096633812063373625278472900390625 Formatted: 6.209 BigDecimal: 6.208899999999999863575794734060764312744140625 Formatted: 6.208 ``` In case you don't see it: "6.2089" rounded to 3 digits gives the output "6.208" while "6.2088" gives "6.209" as output. Less is more? The results were good when using Java 5, 6 or 7 but this Java 8 gives me this strange output. Java version: ``` [me@localhost trunk]$ java -version java version "1.8.0_05" Java(TM) SE Runtime Environment (build 1.8.0_05-b13) Java HotSpot(TM) Server VM (build 25.5-b02, mixed mode) ``` EDIT: this is Java 7's output: ``` [me@localhost trunk]$ java Test BigDecimal: 6.208800000000000096633812063373625278472900390625 Formatted: 6.209 BigDecimal: 6.208899999999999863575794734060764312744140625 Formatted: 6.209 ``` Java 7 version: ``` [me@localhost trunk]$ java -version java version "1.7.0_51" Java(TM) SE Runtime Environment (build 1.7.0_51-b13) Java HotSpot(TM) Server VM (build 24.51-b03, mixed mode) ```

Original source

Related problems