[ 
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

Reply via email to