ICU-11808 Missing ArithmeticException when using ICU4J DecimalFormat

X-SVN-Rev: 37909
This commit is contained in:
Craig Cornelius 2015-09-08 23:39:59 +00:00
parent 1af9647af1
commit 1a6b2975d1
3 changed files with 81 additions and 2 deletions

View 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);
}

View 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());

View 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.
}
}
}