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)