Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-7131459

[Fmt-De] DecimalFormat produces wrong format() results when close to a tie

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P4
    • Resolution: Fixed
    • Affects Version/s: 8
    • Fix Version/s: 8
    • Component/s: core-libs
    • Subcomponent:
    • Resolved In Build:
      b75
    • CPU:
      generic
    • OS:
      generic
    • Verification:
      Verified

      Backports

        Description

        When using a DecimalFormat instance in the default recommended way:

        double myDouble = ....;
        NumberFormat nf = NumberFormat.getInstance(); // or NumberFormat.getCurrencyInstance()
        String myStr = nf.format(myDouble);

        the returned string from format(...) will be sometimes wrong when
        the passed double value is close to a tie (like 1.3905d for example).
        Such values are writen in decimal radix as :
        "iiiiii.ff5" in the currency case (getCurrencyInstance()), i.e. 2 fractional digits.
        or
        "iiiiiiii.fff5" in the decimal case (getInstance()), i.e. 3 fractional digits.

        where 'i' represents an integral digit and 'f' represents a fractional digit.

        Example of such value are:
        0.8055d, 1.1015d, 1.1835d, 7.9005d. There are a lot of them.

        These kind of values cannot be represented exactly with the double floating-point encoding format.

        So only an approximation of them is recorded in memory:
        0.8055d => exact value = 0.80549999999999999378275106209912337362766265869140625
        1.1015d => exact value = 1.1014999999999999236166559057892300188541412353515625
        1.1835d => exact value = 1.183499999999999996447286321199499070644378662109375
        7.9005d => exact value = 7.90050000000000007815970093361102044582366943359375

        nf.format(0.8055d); will return "0.806" where it should return "0.805" (see exact value above)
        nf.format(1.1015d); will return "1.102" where it should return "1.101" (see exact value above)
        nf.format(1.1835d); will return "1.184" where it should return "1.183" (see exact value above)
        nf.format(7.9005d); will return "7.9" where it should return "7.901" (see exact value above)

        This will also happen if DecimalFormat instance has not been created using the default usage pattern.
        For example, if the associated pattern requires 5 digits after decimal point when the value is close
        to a tie from the rounding standpoint (fractional part like "fffff5").

        This may be impacting (at from the end-user standpoint) with series of '9' digits:
        like format(9.9995d) returning "10" where it may have to return "9.999".

        Try the small following program that shows the wrong behavior:

            public static void main(String[] args) {
        java.text.NumberFormat nf = java.text.NumberFormat.getInstance();
        double aDouble;
        String myStr;

        aDouble = 0.8055d;
        myStr = nf.format(aDouble);
                System.out.println("format(" + aDouble + ") returns \"" + myStr + "\" where it should return \"0.805\".");
                aDouble = 1.1015d;
        myStr = nf.format(aDouble);
                System.out.println("format(" + aDouble + ") returns \"" + myStr + "\" where it should return \"1.101\".");
                aDouble = 1.1835d;
        myStr = nf.format(aDouble);
                System.out.println("format(" + aDouble + ") returns \"" + myStr + "\" where it should return \"1.183\".");
                aDouble = 7.9005d;
        myStr = nf.format(aDouble);
                System.out.println("format(" + aDouble + ") returns \"" + myStr + "\" where it should return \"7.901\".");
            }

          Issue Links

            Activity

            Hide
            hgupdate HG Updates added a comment -
            URL: http://hg.openjdk.java.net/jdk8/tl/jdk/rev/bc1f16f5566f
            User: darcy
            Date: 2013-01-11 23:39:32 +0000
            Show
            hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk8/tl/jdk/rev/bc1f16f5566f User: darcy Date: 2013-01-11 23:39:32 +0000
            Hide
            hgupdate HG Updates added a comment -
            URL: http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/bc1f16f5566f
            User: lana
            Date: 2013-01-29 18:46:15 +0000
            Show
            hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/bc1f16f5566f User: lana Date: 2013-01-29 18:46:15 +0000
            Hide
            kshefov Konstantin Shefov added a comment -
            Verified jdk 8b81 Linux x64
            Show
            kshefov Konstantin Shefov added a comment - Verified jdk 8b81 Linux x64
            Hide
            alanb Alan Bateman added a comment -
            I've added release-notes=yes to this bug as the behavior change needs to be captured in the compatibility or release notes for 8.
            Show
            alanb Alan Bateman added a comment - I've added release-notes=yes to this bug as the behavior change needs to be captured in the compatibility or release notes for 8.
            Hide
            olagneau Olivier Lagneau added a comment - - edited
            Below is a draft text for compatibility notes for 8 since rounding behavior changes in 8 versus 7:
            ---------------------------------------------------------------------
            Area: Core Libraries / java.text

            Synopsis
              A wrong rounding behavior of JDK7 has been fixed. The rounding behavior of NumberFormat/DecimalFormat format() method has changed when value is very close to a tie sitting exactly at the rounding position specified in the formatting pattern.

            Nature of Incompatibility
              behavioral

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

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

            RFE
              
              7131459
            ---------------------------------------------

            Show
            olagneau Olivier Lagneau added a comment - - edited Below is a draft text for compatibility notes for 8 since rounding behavior changes in 8 versus 7: --------------------------------------------------------------------- Area: Core Libraries / java.text Synopsis   A wrong rounding behavior of JDK7 has been fixed. The rounding behavior of NumberFormat/DecimalFormat format() method has changed when value is very close to a tie sitting exactly at the rounding position specified in the formatting pattern. Nature of Incompatibility   behavioral Description   When using NumberFormat/DecimalFormat classes, the rounding behavior of previous JDK versions was wrong in some corner cases. This wrong behaviour happened when calling format() method with a value that is very close to a tie, while rounding position specified by the pattern of the NumberFormat/DecimalFormat instance used is exactly sitting at the position of the tie. In that case wrong double rounding or erroneous non-rounding behavior happened.  As an example, while using default recommended NumberFormatFormat API form: NumberFormat nf = java.text.NumberFormat.getInstance() followed by nf.format(0.8055d), value 0.8055d is recorded in the computer as 0.80549999999999999378275106209912337362766265869140625 since this value cannot be represented exactly in binary format. Here default rounding rule is "half-even", and the result of calling format() in JDK7 is a wrong output of "0.806", while correct result is "0.805" since 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 ones). RFE      7131459 ---------------------------------------------

              People

              • Assignee:
                olagneau Olivier Lagneau
                Reporter:
                olagneau Olivier Lagneau
              • Votes:
                0 Vote for this issue
                Watchers:
                7 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Imported:
                  Indexed: