Why does DecimalFormat ".#" and "0.#" have different results on 23.0?
Asked Answered
P

2

11

Why does java.text.DecimalFormat evaluate the following results:

new DecimalFormat("0.#").format(23.0)        // result: "23"

new DecimalFormat(".#").format(23.0)         // result: "23.0"

I would have expected the result to be 23 in both cases, because special character # omits zeros. How does the leading special character 0 affect the fraction part? (Tried to match/understand it with the BNF given in javadoc, but failed to do so.)

Pirate answered 22/3, 2016 at 15:17 Comment(7)
I wonder if ".#" is a valid format and if it shouldn't be #.#, which also results in 23.Arette
@Tom: DecimalFormat(".0") works too. Did not see anything in the javadoc that forbids stuff like ".#".Pirate
"Did not see anything in the javadoc that forbids stuff like ".#"" Me neither, but that doesn't mean the code can handle this correctly. Also that DecimalFormat(".0") works can be coincidence when .# or .0 are invalid and the "fallback" just prints the number, since it would result in the same String ("23.0"). But again, it is just a guess.Arette
Title says 15, example code uses 23. :)Tana
My bad :) Thanks @Bathsheba!Pirate
Interestingly, removing the format string completely also give 23.0Hamer
Good point! Maybe if the pattern is not correct, the input value is returned or something like that. Just guessing of course.. Will have a look at the BNF again.Pirate
H
7

The second format seems to be invalid according to the JavaDoc, but somehow it parses without error anyway.

 Pattern:
         PositivePattern
         PositivePattern ; NegativePattern
 PositivePattern:
         Prefixopt Number Suffixopt
 NegativePattern:
         Prefixopt Number Suffixopt
 Prefix:
         any Unicode characters except \uFFFE, \uFFFF, and special characters
 Suffix:
         any Unicode characters except \uFFFE, \uFFFF, and special characters
 Number:
         Integer Exponentopt
         Integer . Fraction Exponentopt
 Integer:
         MinimumInteger
         #
         # Integer
         # , Integer
 MinimumInteger:
         0
         0 MinimumInteger
         0 , MinimumInteger
 Fraction:
         MinimumFractionopt OptionalFractionopt
 MinimumFraction:
         0 MinimumFractionopt
 OptionalFraction:
         # OptionalFractionopt
 Exponent:
         E MinimumExponent
 MinimumExponent:
         0 MinimumExponentopt

In this case I'd expect the behaviour of the formatter to be undefined. That is, it may produce any old thing and we can't rely on that being consistent or meaningful in any way. So, I don't know why you're getting the 23.0, but you can assume that it's nonsense that you should avoid in your code.

Update: I've just run a debugger through Java 7's DecimalFormat library. The code not only explicitly says that '.#' is allowed, there is a comment in there (java.text.DecimalFormat:2582-2593) that says it's allowed, and an implementation that allows it (line 2597). This seems to be in violation of the documented BNF for the pattern.

Given that this is not documented behaviour, you really shouldn't rely on it as it's liable to change between versions of Java or even library implementations.

Hamer answered 22/3, 2016 at 16:13 Comment(0)
R
3

The following source comment explains the rather unintuitive handling of ".#". Lines 3383-3385 in my DecimalFormat.java file (JDK 8) have the following comment:

// Handle patterns with no '0' pattern character. These patterns
// are legal, but must be interpreted.  "##.###" -> "#0.###".
// ".###" -> ".0##".

Seems like the developers have chosen to interpret ".#" as ".0##", instead of what you expected ("0.#").

Rocha answered 22/3, 2016 at 16:49 Comment(3)
I was just looking at the source code for DecimalFormat and saw this.Anomalistic
I'd already documented that in my answer, but I have different line numbers to you. I wonder what causes that discrepancy? You haven't mentioned which version of java you're referencing here. Can you add that for clarity as it may be responsible?Hamer
I'm using JDK 8, that's the difference.Rocha

© 2022 - 2024 — McMap. All rights reserved.