]> granicus.if.org Git - icu/commitdiff
ICU-13229 Extending range for returning a Long from DecimalFormat#parse(), and changi...
authorShane Carr <shane@unicode.org>
Sat, 17 Jun 2017 01:22:41 +0000 (01:22 +0000)
committerShane Carr <shane@unicode.org>
Sat, 17 Jun 2017 01:22:41 +0000 (01:22 +0000)
X-SVN-Rev: 40175

icu4j/main/classes/core/src/com/ibm/icu/impl/number/Parse.java
icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java
icu4j/main/classes/core/src/com/ibm/icu/text/NumberFormat.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java

index bac26598799cbad60c3c484a7a633e5cb846e246..7477089f5a8929ed72d34736449a38bb430d19b7 100644 (file)
@@ -294,6 +294,10 @@ public class Parse {
               "[\\ '\\u00A0\\u066C\\u2000-\\u200A\\u2018\\u2019\\u202F\\u205F\\u3000\\uFF07]")
           .freeze();
 
+  // For parse return value calculation.
+  private static final BigDecimal MIN_LONG_AS_BIG_DECIMAL = new BigDecimal(Long.MIN_VALUE);
+  private static final BigDecimal MAX_LONG_AS_BIG_DECIMAL = new BigDecimal(Long.MAX_VALUE);
+
   private enum SeparatorType {
     COMMA_LIKE,
     PERIOD_LIKE,
@@ -592,7 +596,8 @@ public class Parse {
       result = result.stripTrailingZeros();
       if (forceBigDecimal || result.scale() > 0) {
         return result;
-      } else if (-result.scale() + result.precision() <= 18) {
+      } else if (result.compareTo(MIN_LONG_AS_BIG_DECIMAL) >= 0
+          && result.compareTo(MAX_LONG_AS_BIG_DECIMAL) <= 0) {
         return result.longValueExact();
       } else {
         return result.toBigIntegerExact();
index 4d9602241904eac45bc3164da5993c42914e4c43..a2baa0a84d5115a46e01634c2c1a4b349230cc86 100644 (file)
@@ -2083,19 +2083,12 @@ public class DecimalFormat extends NumberFormat {
   }
 
   /**
-   * Whether to force {@link #parse} to always return a BigDecimal. By default, {@link #parse} will
-   * return different data types as follows:
+   * Whether to make {@link #parse} prefer returning a {@link com.ibm.icu.math.BigDecimal} when
+   * possible. For strings corresponding to return values of Infinity, -Infinity, NaN, and -0.0, a
+   * Double will be returned even if ParseBigDecimal is enabled.
    *
-   * <ol>
-   *   <li>If the number is an integer (has no fraction part), return a Long if possible, or else a
-   *       BigInteger.
-   *   <li>Otherwise, return a BigDecimal.
-   * </ol>
-   *
-   * If this setting is enabled, a BigDecimal will be returned even if the number is an integer.
-   *
-   * @param value true to cause {@link #parse} to always return a BigDecimal; false to let {@link
-   *     #parse} return different data types.
+   * @param value true to cause {@link #parse} to prefer BigDecimal; false to let {@link #parse}
+   *     return additional data types like Long or BigInteger.
    * @category Parsing
    * @stable ICU 3.6
    */
index 79177be4d03117804f102d887c4b06c5f3324f64..35216fbce770efd5927d60207d712f7037bfda98 100644 (file)
@@ -413,13 +413,19 @@ public abstract class NumberFormat extends UFormat {
 
     /**
      * Returns a Long if possible (e.g., within the range [Long.MIN_VALUE,
-     * Long.MAX_VALUE] and with no decimals), otherwise a Double.
-     * If IntegerOnly is set, will stop at a decimal
+     * Long.MAX_VALUE] and with no decimals); otherwise, returns another type,
+     * such as a BigDecimal, BigInteger, or Double. The return type is not
+     * guaranteed other than for the Long case.
+     *
+     * <p>If IntegerOnly is set, will stop at a decimal
      * point (or equivalent; e.g., for rational numbers "1 2/3", will stop
      * after the 1).
-     * Does not throw an exception; if no object can be parsed, index is
+     *
+     * <p>Does not throw an exception; if no object can be parsed, index is
      * unchanged!
+     *
      * @see #isParseIntegerOnly
+     * @see DecimalFormat#setParseBigDecimal
      * @see java.text.Format#parseObject(String, ParsePosition)
      * @stable ICU 2.0
      */
index f4fc9948d0b0428d91d8467957959625647771b2..8390a0e3526ddf01538811b5a2c85533666cc3bc 100644 (file)
@@ -2802,11 +2802,18 @@ public class NumberFormatTest extends TestFmwk {
 
     @Test
     public void TestParseReturnType() {
-        String[] defaultNonBigDecimals = {
-                "123",      // Long
-                "123.0",    // Long
-                "0.0",      // Long
-                "12345678901234567890"      // BigInteger
+        String[] defaultLong = {
+                "123",
+                "123.0",
+                "0.0",
+                "-9223372036854775808", // Min Long
+                "9223372036854775807" // Max Long
+        };
+
+        String[] defaultNonLong = {
+                "12345678901234567890",
+                "9223372036854775808",
+                "-9223372036854775809"
         };
 
         String[] doubles = {
@@ -2823,14 +2830,25 @@ public class NumberFormatTest extends TestFmwk {
         }
 
         // isParseBigDecimal() is false
-        for (int i = 0; i < defaultNonBigDecimals.length; i++) {
+        for (int i = 0; i < defaultLong.length; i++) {
+            try {
+                Number n = nf.parse(defaultLong[i]);
+                if (!(n instanceof Long)) {
+                    errln("FAIL: parse does not return Long instance");
+                }
+            } catch (ParseException e) {
+                errln("parse of '" + defaultLong[i] + "' threw exception: " + e);
+            }
+        }
+        for (int i = 0; i < defaultNonLong.length; i++) {
             try {
-                Number n = nf.parse(defaultNonBigDecimals[i]);
-                if (n instanceof BigDecimal) {
-                    errln("FAIL: parse returns BigDecimal instance");
+                Number n = nf.parse(defaultNonLong[i]);
+                // For backwards compatibility with this test, BigDecimal is checked.
+                if ((n instanceof Long) || (n instanceof BigDecimal)) {
+                    errln("FAIL: parse returned a Long or a BigDecimal");
                 }
             } catch (ParseException e) {
-                errln("parse of '" + defaultNonBigDecimals[i] + "' threw exception: " + e);
+                errln("parse of '" + defaultNonLong[i] + "' threw exception: " + e);
             }
         }
         // parse results for doubls must be always Double
@@ -2852,14 +2870,15 @@ public class NumberFormatTest extends TestFmwk {
         }
 
         // isParseBigDecimal() is true
-        for (int i = 0; i < defaultNonBigDecimals.length; i++) {
+        for (int i = 0; i < defaultLong.length + defaultNonLong.length; i++) {
+            String input = (i < defaultLong.length) ? defaultLong[i] : defaultNonLong[i - defaultLong.length];
             try {
-                Number n = nf.parse(defaultNonBigDecimals[i]);
+                Number n = nf.parse(input);
                 if (!(n instanceof BigDecimal)) {
                     errln("FAIL: parse does not return BigDecimal instance");
                 }
             } catch (ParseException e) {
-                errln("parse of '" + defaultNonBigDecimals[i] + "' threw exception: " + e);
+                errln("parse of '" + input + "' threw exception: " + e);
             }
         }
         // parse results for doubls must be always Double