- Do not depend on ArithmeticException string in ICU4J.
- Return correct string in ICU4C.
- Fix related issue in applyMaxInteger.
// Older ICUs called uprv_decNumberToString here, which is not exactly the same as
// DecimalQuantity::toScientificString(). The biggest difference is that uprv_decNumberToString does
// not print scientific notation for magnitudes greater than -5 and smaller than some amount (+5?).
- if (fDecimalQuantity->isZero()) {
+ if (fDecimalQuantity->isInfinite()) {
+ fDecimalStr->append("Infinity", status);
+ } else if (fDecimalQuantity->isNaN()) {
+ fDecimalStr->append("NaN", status);
+ } else if (fDecimalQuantity->isZero()) {
fDecimalStr->append("0", -1, status);
} else if (fType==kLong || fType==kInt64 || // use toPlainString for integer types
(fDecimalQuantity->getMagnitude() != INT32_MIN && std::abs(fDecimalQuantity->getMagnitude()) < 5)) {
return;
}
+ if (maxInt <= scale) {
+ setBcdToZero();
+ return;
+ }
+
int32_t magnitude = getMagnitude();
if (maxInt <= magnitude) {
popFromLeft(magnitude - maxInt + 1);
}
void DecimalQuantity::popFromLeft(int32_t numDigits) {
+ U_ASSERT(numDigits <= precision);
if (usingBytes) {
int i = precision - 1;
for (; i >= precision - numDigits; i--) {
u"00.08765",
u"00.008765",
u"00");
+
+ assertFormatSingle(
+ u"Integer Width Remove All A",
+ u"integer-width/00",
+ NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)),
+ "en",
+ 2500,
+ u"00");
+
+ assertFormatSingle(
+ u"Integer Width Remove All B",
+ u"integer-width/00",
+ NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)),
+ "en",
+ 25000,
+ u"00");
+
+ assertFormatSingle(
+ u"Integer Width Remove All B, Bytes Mode",
+ u"integer-width/00",
+ NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)),
+ "en",
+ // Note: this double produces all 17 significant digits
+ 10000000000000002000.0,
+ u"00");
}
void NumberFormatterApiTest::symbols() {
assertEquals(u"Should not overflow",
u"3E-2147483648",
{sp.data(), sp.length(), US_INV});
+
+ // Test largest parseable exponent
+ result = Formattable();
+ nf->parse(u"9876e2147483643", result, status);
+ sp = result.getDecimalNumber(status);
+ assertEquals(u"Should not overflow",
+ u"9.876E+2147483646",
+ {sp.data(), sp.length(), US_INV});
+
+ // Test max value as well
+ const char16_t* infinityInputs[] = {
+ u"9876e2147483644",
+ u"9876e2147483645",
+ u"9876e2147483646",
+ u"9876e2147483647",
+ u"9876e2147483648",
+ u"9876e2147483649",
+ };
+ for (const auto& input : infinityInputs) {
+ result = Formattable();
+ nf->parse(input, result, status);
+ sp = result.getDecimalNumber(status);
+ assertEquals(UnicodeString("Should become Infinity: ") + input,
+ u"Infinity",
+ {sp.data(), sp.length(), US_INV});
+ }
}
void NumberFormatTest::Test13840_ParseLongStringCrash() {
return;
}
+ if (maxInt <= scale) {
+ setBcdToZero();
+ return;
+ }
+
int magnitude = getMagnitude();
if (maxInt <= magnitude) {
popFromLeft(magnitude - maxInt + 1);
if (precision != 0) {
scale = Utility.addExact(scale, delta);
origDelta = Utility.addExact(origDelta, delta);
+ // Make sure that precision + scale won't overflow, either
+ Utility.addExact(scale, precision);
}
}
@Override
protected void popFromLeft(int numDigits) {
+ assert numDigits <= precision;
if (usingBytes) {
int i = precision - 1;
for (; i >= precision - numDigits; i--) {
tempLong = tempLong * 10 + getDigitPos(shift);
}
BigDecimal result = BigDecimal.valueOf(tempLong);
- try {
+ // Test that the new scale fits inside the BigDecimal
+ long newScale = result.scale() + scale;
+ if (newScale <= Integer.MIN_VALUE) {
+ result = BigDecimal.ZERO;
+ } else {
result = result.scaleByPowerOfTen(scale);
- } catch (ArithmeticException e) {
- if (e.getMessage().contains("Underflow")) {
- result = BigDecimal.ZERO;
- } else {
- throw e;
- }
}
- if (isNegative())
+ if (isNegative()) {
result = result.negate();
+ }
return result;
}
}
result = nf.parse(".0003e-2147483644");
assertEquals("Should not overflow",
"0", result.toString());
+
+ // Test largest parseable exponent
+ // This is limited by ICU's BigDecimal implementation
+ result = nf.parse("1e999999999");
+ assertEquals("Should not overflow",
+ "1E+999999999", result.toString());
+
+ // Test max value as well
+ String[] infinityInputs = {
+ "9876e1000000000",
+ "9876e2147483640",
+ "9876e2147483641",
+ "9876e2147483642",
+ "9876e2147483643",
+ "9876e2147483644",
+ "9876e2147483645",
+ "9876e2147483646",
+ "9876e2147483647",
+ "9876e2147483648",
+ "9876e2147483649",
+ };
+ for (String input : infinityInputs) {
+ result = nf.parse(input);
+ assertEquals("Should become Infinity: " + input,
+ "Infinity", result.toString());
+ }
}
@Test
"00.08765",
"00.008765",
"00");
+
+ assertFormatSingle(
+ "Integer Width Remove All A",
+ "integer-width/00",
+ NumberFormatter.with().integerWidth(IntegerWidth.zeroFillTo(2).truncateAt(2)),
+ ULocale.ENGLISH,
+ 2500,
+ "00");
+
+ assertFormatSingle(
+ "Integer Width Remove All B",
+ "integer-width/00",
+ NumberFormatter.with().integerWidth(IntegerWidth.zeroFillTo(2).truncateAt(2)),
+ ULocale.ENGLISH,
+ 25000,
+ "00");
+
+ assertFormatSingle(
+ "Integer Width Remove All B, Bytes Mode",
+ "integer-width/00",
+ NumberFormatter.with().integerWidth(IntegerWidth.zeroFillTo(2).truncateAt(2)),
+ ULocale.ENGLISH,
+ // Note: this double produces all 17 significant digits
+ 10000000000000002000.0,
+ "00");
}
@Test