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

Wrong behavior of DecimalFormat with RoundingMode.UP in special case

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Unresolved
    • Icon: P4 P4
    • 25
    • core-libs
    • None
    • behavioral
    • low
    • Hide
      This is an update to Decimal Format to fix the behavior of a particular edge cases involving a fractional floating-point value being incorrectly formatted as zero under the right circumstances. This would cause any user, who's formatting falls under this special case to potentially see different results depending on the rounding mode. However, the existing behavior is wrong and should be corrected.
      Show
      This is an update to Decimal Format to fix the behavior of a particular edge cases involving a fractional floating-point value being incorrectly formatted as zero under the right circumstances. This would cause any user, who's formatting falls under this special case to potentially see different results depending on the rounding mode. However, the existing behavior is wrong and should be corrected.
    • Java API
    • SE

      Summary

      Correct DecimalFormat’s implementation to handle an edge case when formatting a fractional floating-point value would return a zero string, violating the UP, CEILING, and FLOOR RoundingMode contracts.

      Problem

      DecimalFormat, when formatting a floating-point value, will first make a conversion from a floating-point value to a string representation, (from here on, out referred to as s). s is then truncated and rounded under the DecimalFormat pattern and RoundingMode to create the resultant string returned.

      In this particular edge case, if the maximum fractional digits given by the DecimalFormat pattern is less than the amount of leading zeroes in the fractional portion of s, DecimalFormat incorrectly returned a zero string, instead of considering rounding. By not considering rounding, formatting certain floating-point values violated the UP, CEILING, and FLOOR RoundingMode contracts. Specifically, the stipulation: "Note that this rounding mode never decreases the magnitude of the calculated value".

      For example, consider a DecimalFormat with pattern “0.0” and RoundingMode.UP which formats the numerical value .001. This numerical value, which is a representation of the floating-point value 0.001000000000000000020816681711721685132943093776702880859375 is converted to the decimal string “0.001” by DecimalFormat. The existing implementation assumes it can return zero as the fractional precision (1) given by the DecimalFormat pattern is less than the count of fractional leading zeros (2) in the decimal string. However, returning the formatted string "0.0" violates the RoundingMode.UP contract and should have been "0.1".

      Solution

      Ensure that rounding is considered, even if the maximum fractional digits allowed by the DecimalFormat pattern is less than the leading fractional zeroes given by s for formatting a fractional floating-point value.

      Given the double value 0.00010000000000000000479217... represented by the numerical value 0.0001, the following is an example of the behavioral changes under every RoundingMode with a "0.00" pattern DecimalFormat. Unless marked as different, the results are the same as before the change.

      0.0001 formatted with 0.00 and mode UP gives 0.01 (previously, 0.00)
      0.0001 formatted with 0.00 and mode DOWN gives 0.00
      0.0001 formatted with 0.00 and mode CEILING gives 0.01 (previously, 0.00)
      0.0001 formatted with 0.00 and mode FLOOR gives 0.00
      0.0001 formatted with 0.00 and mode HALF_UP gives 0.00
      0.0001 formatted with 0.00 and mode HALF_DOWN gives 0.00
      0.0001 formatted with 0.00 and mode HALF_EVEN gives 0.00
      -0.0001 formatted with 0.00 and mode UP gives -0.01 (previously, -0.00)
      -0.0001 formatted with 0.00 and mode DOWN gives -0.00
      -0.0001 formatted with 0.00 and mode CEILING gives -0.00
      -0.0001 formatted with 0.00 and mode FLOOR gives -0.01 (previously, -0.00)
      -0.0001 formatted with 0.00 and mode HALF_UP gives -0.00
      -0.0001 formatted with 0.00 and mode HALF_DOWN gives -0.00
      -0.0001 formatted with 0.00 and mode HALF_EVEN gives -0.00 

      Note: This change does not affect the case where the DecimalFormat maximum fractional digits is equivalent to the leading fractional zeroes given by s. Rounding behavior for that case remains the same. For example, the double value 0.0500000000000000027755... given by the numerical value 0.05 would still format to 0.1 under a "0.0" DecimalFormat pattern with HALF_UP. (This behavior correctly occurs before and after this change).

      Specification

      N/A (behavioral change only)

            jlu Justin Lu
            webbuggrp Webbug Group
            Naoto Sato
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: