hadoop-common-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Chris Nauroth (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (HADOOP-9252) StringUtils.limitDecimalTo2(..) is unnecessarily synchronized
Date Sat, 02 Feb 2013 01:09:11 GMT

    [ 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

Mime
View raw message