From d0d0b173b427322fe76c5a91abfd06dd1be3dade Mon Sep 17 00:00:00 2001 From: Shane Carr Date: Fri, 26 May 2017 23:59:13 +0000 Subject: [PATCH] ICU-13205 Prevent exception from being thrown when parsing numbers with very large exponents. X-SVN-Rev: 40141 --- .../src/com/ibm/icu/text/DecimalFormat.java | 27 +++++++++++++++++-- .../icu/dev/test/format/NumberFormatTest.java | 27 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java b/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java index 17e0b9779c5..e1f5acef3d4 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java @@ -802,7 +802,7 @@ public class DecimalFormat extends NumberFormat { Number result = Parse.parse(text, parsePosition, pprops, symbols); // Backwards compatibility: return com.ibm.icu.math.BigDecimal if (result instanceof java.math.BigDecimal) { - result = new com.ibm.icu.math.BigDecimal((java.math.BigDecimal) result); + result = safeConvertBigDecimal((java.math.BigDecimal) result); } return result; } @@ -820,7 +820,7 @@ public class DecimalFormat extends NumberFormat { Number number = result.getNumber(); // Backwards compatibility: return com.ibm.icu.math.BigDecimal if (number instanceof java.math.BigDecimal) { - number = new com.ibm.icu.math.BigDecimal((java.math.BigDecimal) number); + number = safeConvertBigDecimal((java.math.BigDecimal) number); result = new CurrencyAmount(number, result.getCurrency()); } return result; @@ -2438,6 +2438,29 @@ public class DecimalFormat extends NumberFormat { formatter.export(exportedProperties); } + /** + * Converts a java.math.BigDecimal to a com.ibm.icu.math.BigDecimal with fallback for numbers + * outside of the range supported by com.ibm.icu.math.BigDecimal. + * + * @param number + * @return + */ + private Number safeConvertBigDecimal(java.math.BigDecimal number) { + try { + return new com.ibm.icu.math.BigDecimal(number); + } catch (NumberFormatException e) { + if (number.signum() > 0 && number.scale() < 0) { + return Double.POSITIVE_INFINITY; + } else if (number.scale() < 0) { + return Double.NEGATIVE_INFINITY; + } else if (number.signum() < 0) { + return -0.0; + } else { + return 0.0; + } + } + } + /** * Updates the property bag with settings from the given pattern. * diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java index 8a2d81133a8..cf9a2adf78b 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java @@ -5284,6 +5284,33 @@ public class NumberFormatTest extends TestFmwk { expect2(df, 35.0, "$35.0"); } + @Test + public void testParseVeryVeryLargeExponent() { + DecimalFormat df = new DecimalFormat(); + ParsePosition ppos = new ParsePosition(0); + + Object[][] cases = { + {"1.2E+1234567890", Double.POSITIVE_INFINITY}, + {"1.2E+999999999", new com.ibm.icu.math.BigDecimal("1.2E+999999999")}, + {"1.2E+1000000000", Double.POSITIVE_INFINITY}, + {"-1.2E+999999999", new com.ibm.icu.math.BigDecimal("-1.2E+999999999")}, + {"-1.2E+1000000000", Double.NEGATIVE_INFINITY}, + {"1.2E-999999999", new com.ibm.icu.math.BigDecimal("1.2E-999999999")}, + {"1.2E-1000000000", 0.0}, + {"-1.2E-999999999", new com.ibm.icu.math.BigDecimal("-1.2E-999999999")}, + {"-1.2E-1000000000", -0.0}, + + }; + + for (Object[] cas : cases) { + ppos.setIndex(0); + String input = (String) cas[0]; + Number expected = (Number) cas[1]; + Number actual = df.parse(input, ppos); + assertEquals(input, expected, actual); + } + } + @Test public void testParseGroupingMode() { ULocale[] locales = { // GROUPING DECIMAL