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

[Fmt-De] DecimalFormat produces wrong format() results in a few non HALF_* corner cases

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • 8, 9
    • core-libs
    • Fix Understood
    • generic
    • generic

      Calling DecimalFormat.format(double ...) when rounding mode is one of UP, DOWN, CEILING, FLOOR, UNNECESSARY will bring wrong rounding decision from DigitList.shouldRoundUp due to roumding-up/truncation of digits already happening in Double.toString() (more precisely sun.misc.FloatingDecimal.dtoa() called from toString()).

      This will happen when dtoa() pre- rounding/truncation happens exactly at the DecimalFormat.maximumFractionDigits position

      This is a long-standing bug (pre 9) that is an equivalent to JDK-7131459 for non HALF_* cases.
      In that case threshold digit is not '5' (i.e. tie value) as in HALF_* modes, but '0' digit.

      For example rounding at 2nd fractional digits position the input value "1.26" with a DecimalFormat.format()
      call, using UP rounding mode, will WRONGLY provide 1.26 while it should provide 1.27 since best binary approximation is in fact a big greater (1.2600000000000000088817841970012523233890533447265625
       ) than 1.26.
      In this case dtoa() truncated the result, thus suppressing the remaining digits that should be taken into account and which should cause rounding-up. DigitList.shouldRoundUp() should take into account pre- rounding-up/truncation from dtoa().

      There 12 such errors for non HALF_* rounding modes. Below is the list of those :
      // ***** Rounding errors in DigitList.ShouldRoundUp when non HALF_* rounding
      // ***** happening when no more digits after the fractional rounding position
      // ***** All these errors are due to sun.misc.FloatingDecimal.dtoa()
      // ***** rounding-up/truncating the digits due to constraints of IEEE-754
      // ***** dtoa() is called from Double.toString() call.

      DecimalFormat corner cases rounding for NON HALF_* rules
      DecimalFormat rounding at 2nd Fractional position

      =============== UP rounding mode "on threshold" cases ==============
      --------------- Positive Values -------------
      Value above threshold at rounding position : 1.26
      Default output for 1.26 -> 1.26
      BigDecimal output for 1.26 -> 1.2600000000000000088817841970012523233890533447265625
      Best binary approximation (abs value) above threshold : truncated.
      ==> SHOULD be rounded (UP). Expected 1.27
      DecimalFormat.format() output for 1.26 -> 1.26

      --------------- Negative Values -------------
      ==> UP rounding-mode similar on negative values (-1.1 --> -2) ...
      Value above threshold at rounding position : -1.26
      Default output for -1.26 -> -1.26
      BigDecimal output for -1.26 -> -1.2600000000000000088817841970012523233890533447265625
      Best binary approximation (abs value) above threshold : truncated.
      ==> SHOULD be rounded (UP). Expected -1.27
      DecimalFormat.format() output for -1.26 -> -1.26

      End =============== UP rounding mode "on threshold" cases ============== End

      =============== DOWN rounding mode "on threshold" cases ==============
      --------------- Positive Values -------------
      Value below threshold at rounding position : 1.24
      Default output for 1.24 -> 1.24
      BigDecimal output for 1.24 -> 1.2399999999999999911182158029987476766109466552734375
      Best binary approximation (abs value) below threshold : rounded-up.
      ==> SHOULD be rounded (DOWN). Expected 1.23
      DecimalFormat.format() output for 1.24 -> 1.24

      --------------- Negative Values -------------
      ==> DOWN rounding-mode similar on negative values (-1.1 --> -1) ...
      Value below threshold at rounding position : -1.24
      Default output for -1.24 -> -1.24
      BigDecimal output for -1.24 -> -1.2399999999999999911182158029987476766109466552734375
      Best binary approximation (abs value) below threshold : rounded-up.
      ==> SHOULD be rounded (DOWN). Expected -1.23
      DecimalFormat.format() output for -1.24 -> -1.24

      End =============== DOWN rounding mode "on threshold" cases ============== End

      =============== CEILING rounding mode "on threshold" cases ==============
      --------------- Positive Values -------------
      Value above threshold at rounding position : 1.26
      Default output for 1.26 -> 1.26
      BigDecimal output for 1.26 -> 1.2600000000000000088817841970012523233890533447265625
      Best binary approximation (abs value) above threshold : truncated.
      ==> SHOULD be rounded (CEILING). Expected 1.27
      DecimalFormat.format() output for 1.26 -> 1.26

      --------------- Negative Values -------------
      ==> CEILING rounding-mode different on negative values (-1.1 --> -1) ...
      Value below threshold at rounding position : -1.24
      Default output for -1.24 -> -1.24
      BigDecimal output for -1.24 -> -1.2399999999999999911182158029987476766109466552734375
      Best binary approximation (abs value) below threshold : rounded-up.
      ==> SHOULD be rounded (CEILING). Expected -1.23
      DecimalFormat.format() output for -1.24 -> -1.24

      End =============== CEILING rounding mode "on threshold" cases ============== End

      =============== FLOOR rounding mode "on threshold" cases ==============
      --------------- Positive Values -------------
      Value below threshold at rounding position : 1.24
      Default output for 1.24 -> 1.24
      BigDecimal output for 1.24 -> 1.2399999999999999911182158029987476766109466552734375
      Best binary approximation (abs value) below threshold : rounded-up.
      ==> SHOULD be rounded (FLOOR). Expected 1.23
      DecimalFormat.format() output for 1.24 -> 1.24

      --------------- Negative Values -------------
      ==> FLOOR rounding-mode different on negative values (-1.1 --> -2) ...
      Value above threshold at rounding position : -1.26
      Default output for -1.26 -> -1.26
      BigDecimal output for -1.26 -> -1.2600000000000000088817841970012523233890533447265625
      Best binary approximation (abs value) above threshold : truncated.
      ==> SHOULD be rounded (FLOOR). Expected -1.27
      DecimalFormat.format() output for -1.26 -> -1.26

      End =============== FLOOR rounding mode "on threshold" cases ============== End

      =============== UNNECESSARY rounding mode "on threshold" cases ==============
      --------------- Positive Values -------------
      Value below threshold at rounding position : 1.24
      Default output for 1.24 -> 1.24
      BigDecimal output for 1.24 -> 1.2399999999999999911182158029987476766109466552734375
      Best binary approximation (abs value) below threshold : rounded-up.
      ==> SHOULD throw ArithmeticException !
      DecimalFormat.format() output for 1.24 -> 1.24

      Value above threshold at rounding position : 1.26
      Default output for 1.26 -> 1.26
      BigDecimal output for 1.26 -> 1.2600000000000000088817841970012523233890533447265625
      Best binary approximation (abs value) above threshold : truncated.
      ==> SHOULD throw ArithmeticException !
      DecimalFormat.format() output for 1.26 -> 1.26

      --------------- Negative Values -------------
      ==> UNNECESSARY rounding-mode similar on negative values (ArithmeticException thrown) ...
      Value below threshold at rounding position : -1.24
      Default output for -1.24 -> -1.24
      BigDecimal output for -1.24 -> -1.2399999999999999911182158029987476766109466552734375
      Best binary approximation (abs value) below threshold : rounded-up.
      ==> SHOULD throw ArithmeticException !
      DecimalFormat.format() output for -1.24 -> -1.24

      Value above threshold at rounding position : -1.26
      Default output for -1.26 -> -1.26
      BigDecimal output for -1.26 -> -1.2600000000000000088817841970012523233890533447265625
      Best binary approximation (abs value) above threshold : truncated.
      ==> SHOULD throw ArithmeticException !
      DecimalFormat.format() output for -1.26 -> -1.26

      End =============== UNNECESSARY rounding mode "on threshold" cases ============== End


            jlu Justin Lu
            olagneau Olivier Lagneau (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: