]> granicus.if.org Git - icu/commitdiff
ICU-11808 Missing ArithmeticException when using ICU4J DecimalFormat
authorCraig Cornelius <ccornelius@google.com>
Tue, 8 Sep 2015 23:39:59 +0000 (23:39 +0000)
committerCraig Cornelius <ccornelius@google.com>
Tue, 8 Sep 2015 23:39:59 +0000 (23:39 +0000)
X-SVN-Rev: 37909

icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java
icu4j/main/classes/core/src/com/ibm/icu/text/DigitList.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java

index 3a938e9593ff70282085ea2e52932e253a930e25..1995f682a6da8bcf327fb6cff6d2cb645f12ca8b 100644 (file)
@@ -1123,6 +1123,10 @@ public class DecimalFormat extends NumberFormat {
         number *= multiplier;
         synchronized (digitList) {
             digitList.set(number, precision(true));
+            // Issue 11808
+            if (digitList.wasRounded() && roundingMode == BigDecimal.ROUND_UNNECESSARY) {
+                throw new ArithmeticException("Rounding necessary");              
+            }
             return subformat(number, result, fieldPosition, isNegative, true, parseAttr);
         }
     }
@@ -1154,6 +1158,10 @@ public class DecimalFormat extends NumberFormat {
         // number.
         synchronized (digitList) {
             digitList.set(number, precision(true));
+            // For issue 11808.
+            if (digitList.wasRounded() && roundingMode == BigDecimal.ROUND_UNNECESSARY) {
+                throw new ArithmeticException("Rounding necessary");              
+            }
             return subformat(number.intValue(), result, fieldPosition, number.signum() < 0, true,
                              parseAttr);
         }
@@ -1184,6 +1192,10 @@ public class DecimalFormat extends NumberFormat {
         synchronized (digitList) {
             digitList.set(number, precision(false), !useExponentialNotation &&
                           !areSignificantDigitsUsed());
+            // For issue 11808.
+            if (digitList.wasRounded() && roundingMode == BigDecimal.ROUND_UNNECESSARY) {
+                throw new ArithmeticException("Rounding necessary");              
+            }
             return subformat(number.doubleValue(), result, fieldPosition, number.signum() < 0,
                              false, parseAttr);
         }
@@ -1213,6 +1225,10 @@ public class DecimalFormat extends NumberFormat {
         synchronized (digitList) {
             digitList.set(number, precision(false), !useExponentialNotation &&
                           !areSignificantDigitsUsed());
+            // For issue 11808.
+            if (digitList.wasRounded() && roundingMode == BigDecimal.ROUND_UNNECESSARY) {
+                throw new ArithmeticException("Rounding necessary");              
+            }
             return subformat(number.doubleValue(), result, fieldPosition, number.signum() < 0,
                              false, false);
         }
index 9ef9d1ada0da1821d58a20b1dd891838df1068df..e238472784426acb2967fe9ddcddeb032cfa1bec 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 1996-2011, International Business Machines Corporation and    *
+ * Copyright (C) 1996-2015, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -411,6 +411,8 @@ final class DigitList {
         // DDDDDE+/-DDDDD.
         String rep = Double.toString(source);
 
+        didRound = false;
+
         set(rep, MAX_LONG_DIGITS);
 
         if (fixedPoint) {
@@ -552,10 +554,12 @@ final class DigitList {
                         digits[0] = (byte) '1';
                         ++decimalAt;
                         maximumDigits = 0; // Adjust the count
+                        didRound = true;
                         break;
                     }
 
                     ++digits[maximumDigits];
+                    didRound = true;
                     if (digits[maximumDigits] <= '9') break;
                     // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
                 }
@@ -571,6 +575,18 @@ final class DigitList {
         }
     }
 
+    // Value to indicate that rounding was done. 
+    private boolean didRound = false;
+    
+    /**
+     * Indicates if last digit set was rounded or not.
+     * true indicates it was rounded.
+     * false indicates rounding has not been done.
+     */
+    public boolean wasRounded() {
+        return didRound;
+    }
+    
     /**
      * Utility routine to set the value of the digit list from a long
      */
@@ -596,6 +612,8 @@ final class DigitList {
         // which is outside the legal range of a long, but which can
         // be represented by DigitList.
         // [NEW] Faster implementation
+        didRound = false;
+        
         if (source <= 0) {
             if (source == Long.MIN_VALUE) {
                 decimalAt = count = MAX_LONG_DIGITS;
@@ -634,7 +652,8 @@ final class DigitList {
         String stringDigits = source.toString();
 
         count = decimalAt = stringDigits.length();
-
+        didRound = false;
+        
         // Don't copy trailing zeros
         while (count > 1 && stringDigits.charAt(count - 1) == '0') --count;
 
@@ -715,6 +734,8 @@ final class DigitList {
 //|            }
 //|        }
 
+        didRound = false;
+
         // The maxDigits here could also be Integer.MAX_VALUE
         set(stringDigits, stringDigits.length());
 
index 681b21aa5c3c2ca78d279bba478c5eb27cd2651e..a33b598fedb0ce3478ed740b7df35fcaeb31f5d5 100644 (file)
@@ -4256,4 +4256,46 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
         new NumberFormatTestTuple().toString();
     }
 
+    // Testing for Issue 11808.
+    public void TestRoundUnnecessarytIssue11808 () {
+        DecimalFormat df = (DecimalFormat) DecimalFormat.getInstance();
+        StringBuffer result = new StringBuffer("");
+        df.setRoundingMode(BigDecimal.ROUND_UNNECESSARY);
+        df.applyPattern("00.0#E0");
+        
+        try {
+            df.format(99999.0, result, new FieldPosition(0));
+            fail("Missing ArithmeticException for double: " + result);
+        } catch (ArithmeticException expected) {
+            // The exception should be thrown, since rounding is needed.
+        }
+
+        try {
+            result = df.format(99999, result, new FieldPosition(0));
+            fail("Missing ArithmeticException for int: " + result);
+       } catch (ArithmeticException expected) {
+           // The exception should be thrown, since rounding is needed.
+        }
+
+        try {
+            result = df.format(new BigInteger("999999"), result, new FieldPosition(0));
+            fail("Missing ArithmeticException for BigInteger: " + result);
+        } catch (ArithmeticException expected) {
+            // The exception should be thrown, since rounding is needed.
+        }
+
+        try {
+            result = df.format(new BigDecimal("99999"), result, new FieldPosition(0));
+            fail("Missing ArithmeticException for BigDecimal: " + result);
+        } catch (ArithmeticException expected) {
+            // The exception should be thrown, since rounding is needed.
+        }
+        
+        try {
+            result = df.format(new BigDecimal("-99999"), result, new FieldPosition(0));
+            fail("Missing ArithmeticException for BigDecimal: " + result);
+        } catch (ArithmeticException expected) {
+            // The exception should be thrown, since rounding is needed.
+        }
+    }
 }