Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArchiveUtils.doubleToString() rounding fails unit test under Java 8 #31

Closed
kris-sigur opened this issue Sep 30, 2014 · 6 comments
Closed

Comments

@kris-sigur
Copy link
Member

Possibly an issue with Java 8.

The unit test fails when using JDK 1.8. 12.345 should be rounded to 12.34 but is rounded to 12.35 instead.

At first I thought the default rounding mode had been changed, but even setting it explicitly did not resolve the issue.

Not sure of the impact, but it is a little troubling that the same input could give different output based on whether you are using Java 8 or Java 7 to run the program.

@anjackson
Copy link
Member

I'm confused - 12.35 is the correct answer for HALF_EVEN rounding. To get 12.34 you'd need to use RoundingMode.DOWN. Is this another odd Locale issue?

@anjackson
Copy link
Member

EDIT: I was mistake in the previous comment. The 12.35 figure is what I'd expect for normal rounding, but this class has long defaulted to HALF_EVEN which means 'round to the even number', and so should produce 12.34.

From the Java 8 compatibility guidelines:

When using the NumberFormat and DecimalFormat classes, the rounding behavior of previous versions of the JDK was wrong in some corner cases. This wrong behaviour happened when calling the format() method with a value that was very close to a tie, where the rounding position specified by the pattern of the NumberFormat or DecimalFormat instance was exactly sitting at the position of the tie. In that case, the wrong double rounding or erroneous non-rounding behavior occurred.

As an example, when using the default recommended NumberFormatFormat API form: NumberFormat nf = java.text.NumberFormat.getInstance() followed by nf.format(0.8055d), the value 0.8055d is recorded in the computer as 0.80549999999999999378275106209912337362766265869140625 since this value cannot be represented exactly in the binary format. Here, the default rounding rule is "half-even", and the result of calling format() in JDK 7 is a wrong output of "0.806", while the correct result is "0.805", since the value recorded in memory by the computer is "below" the tie.

This new behavior is also implemented for all rounding positions that might be defined by any pattern chosen by the programmer (non default patterns).

The related bug is here, but I'm not sure this can be responsible unless that fix broke the behaviour elsewhere.

EDIT: That direct link to the bug doesn't seem to work, sometimes? You may have to go via the compatibility report page.

@anjackson
Copy link
Member

Oh weird. Looks like they swapped an old bug for a new one!?

Using this test class:

import java.text.NumberFormat;

public class TestNumberFormatRounding {

    public static void main(String[] args) {
        System.out
                .println("JVM Version: " + System.getProperty("java.version"));

        NumberFormat nf = java.text.NumberFormat.getInstance();
        nf.setMaximumFractionDigits(3);
        nf.setMinimumFractionDigits(0);
        String expected = "0.805";
        String result = nf.format(0.8055d);
        System.out.println("Should print (3 sig.fig.) " + expected + " got "
                + result
                + " - correct? = " + (expected.equals(result)));

        nf.setMaximumFractionDigits(2);
        double test = 12.345;
        expected = "12.34";
        result = nf.format(test);
        System.out.println("Should print (2 sig.fig.) " + expected + " got "
                + result
                + " - correct? = " + (expected.equals(result)));
    }

}

Under Java 7, I get this:

JVM Version: 1.7.0_51
Should print (3 sig.fig.) 0.805 got 0.806 - correct? = false
Should print (2 sig.fig.) 12.34 got 12.34 - correct? = true

But under Java 8:

JVM Version: 1.8.0-ea
Should print (3 sig.fig.) 0.805 got 0.805 - correct? = true
Should print (2 sig.fig.) 12.34 got 12.35 - correct? = false

i.e. they have fixed the first case, but broken the second one.

@kris-sigur
Copy link
Member Author

In that case I suppose we could pick a different number for the unit test (that does round the same on Java 6 to 8) to close this issue.

@anjackson
Copy link
Member

Yes, I'll also file a bug report with Oracle, but it's not worth holding up development for this as it's rather superficial I think.

@kris-sigur
Copy link
Member Author

Just annoying when unit tests fail for no good reason. I'll submit a pull request with a less edgy test case.

kris-sigur added a commit to kris-sigur/webarchive-commons that referenced this issue Sep 30, 2014
Fixes issue iipc#31 which relates to changes in how Java rounds doubles in
some edge cases.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants