[
https://issues.apache.org/jira/browse/HADOOP-9252?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13569335#comment-13569335
]
Chris Nauroth commented on HADOOP-9252:
---------------------------------------
Hi Nicholas,
I'm assuming that for backwards-compatibility, {{StringUtils#limitDecimalTo2}}
still needs to keep returning the same output after this patch. (If that's not
the case, please let me know.)
{code}
- public static synchronized String limitDecimalTo2(double d) {
- return decimalFormat.format(d);
+ /**
+ * @deprecated use {@link String#format(String, Object...)},
+ * i.e. String.format("%.2f", d).
+ */
+ @Deprecated
+ public static String limitDecimalTo2(double d) {
+ return String.format("%.2f", d);
}
{code}
The former DecimalFormat "#.##" is not quite equivalent to the new printf
format "%.2f". The former will truncate the output to an integer if there are
only non-significant digits (zeroes) remaining on the right side of the decimal
point after rounding. The latter always maintains a precision of 2 digits to
the right of the decimal point, even if those digits are zeroes. This is
easiest to see using example inputs like 123 (integral input) or 100.001 (float
input, but only zeroes remaining to the right of the decimal point after
rounding).
Here is a Scala REPL session showing that the 2 forms produce equivalent output
for many cases, but then behave differently for 123 and 100.001.
{code}
scala> def printDouble(x: Double) {
val decimalFormat =
NumberFormat.getInstance(Locale.ENGLISH).asInstanceOf[DecimalFormat]
decimalFormat.applyPattern("#.##")
println("DecimalFormat: " +
decimalFormat.format(x.asInstanceOf[java.lang.Double]))
println("%.2f: " + String.format("%.2f",
x.asInstanceOf[java.lang.Double]))
}
def printDouble(x: Double) {
Of[DecimalFormat]
| decimalFormat.applyPattern("#.##")
ng.Double]))
ang.Double]))
| }
printDouble: (x: Double)Unit
scala> List(123.456, 0.123, 10.01, 123, 100.001) foreach printDouble
List(123.456, 0.123, 10.01, 123, 100.001) foreach printDouble
DecimalFormat: 123.46
%.2f: 123.46
DecimalFormat: 0.12
%.2f: 0.12
DecimalFormat: 10.01
%.2f: 10.01
DecimalFormat: 123
%.2f: 123.00
DecimalFormat: 100
%.2f: 100.00
{code}
Unfortunately, I don't know how to accomplish the same kind of truncation using
printf format codes alone. Maybe we'd have to write our own truncation logic
after the call to {{String#format}}?
There are also differences in handling some edge case values:
{code}
scala> List(Double.MaxValue, Double.MinValue, Double.NaN,
Double.NegativeInfinity, Double.PositiveInfinity) foreach printDouble
y, Double.PositiveInfinity) foreach printDouble
DecimalFormat:
179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
%.2f:
179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00
DecimalFormat:
-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
%.2f:
-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00
DecimalFormat: ?
%.2f: NaN
DecimalFormat: -°
%.2f: -Infinity
DecimalFormat: °
%.2f: Infinity
{code}
Also, the {{NumberFormat}} version of the code had explicitly set locale to
{{Locale.ENGLISH}}. This form of {{String#format}} will use the JVM default
locale, so this might cause surprises if anyone has deployed on a JVM where the
default locale is not English. I suggest using the overload of
{{String#format}} that accepts {{Locale}} and passing in {{Locale.ENGLISH}}.
Thanks!
> StringUtils.limitDecimalTo2(..) is unnecessarily synchronized
> -------------------------------------------------------------
>
> Key: HADOOP-9252
> URL: https://issues.apache.org/jira/browse/HADOOP-9252
> Project: Hadoop Common
> Issue Type: Improvement
> Components: util
> Reporter: Tsz Wo (Nicholas), SZE
> Assignee: Tsz Wo (Nicholas), SZE
> Priority: Minor
> Attachments: c9252_20130127.patch, c9252_20130128.patch
>
>
> limitDecimalTo2(double) currently uses decimalFormat, which is a static
> field, so that it is synchronized. Synchronization is unnecessary since it
> can simply uses String.format(..).
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira