int8_t DecimalQuantity::getDigitPos(int32_t position) const {
if (usingBytes) {
- if (position < 0 || position > precision) { return 0; }
+ if (position < 0 || position >= precision) { return 0; }
return fBCD.bcdBytes.ptr[position];
} else {
if (position < 0 || position >= 16) { return 0; }
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
- int32_t value = 0;
+ uint32_t value = 0;
for (int32_t i = start; i < len; ++i) {
UChar ch = str[i];
if (ch < 0x30 || ch > 0x39) {
}
value = value * 10 - 0x30 + (int32_t) ch;
}
- if (neg) {
- value = -value;
- }
- *static_cast<int32_t *>(intPtr) = value;
+ int32_t signedValue = neg ? -value : static_cast<int32_t>(value);
+ *static_cast<int32_t *>(intPtr) = signedValue;
}
static void intToStr(
const void *intPtr, UnicodeString &appendTo) {
UChar buffer[20];
- int32_t x = *static_cast<const int32_t *>(intPtr);
- UBool neg = FALSE;
- if (x < 0) {
- neg = TRUE;
- x = -x;
- }
- if (neg) {
+ // int64_t such that all int32_t values can be negated
+ int64_t xSigned = *static_cast<const int32_t *>(intPtr);
+ uint32_t x;
+ if (xSigned < 0) {
appendTo.append((UChar)0x2D);
+ x = static_cast<uint32_t>(-xSigned);
+ } else {
+ x = static_cast<uint32_t>(xSigned);
}
- int32_t len = uprv_itou(buffer, UPRV_LENGTHOF(buffer), (uint32_t) x, 10, 1);
+ int32_t len = uprv_itou(buffer, UPRV_LENGTHOF(buffer), x, 10, 1);
appendTo.append(buffer, 0, len);
}
void NumberFormatterApiTest::formatTypes() {
UErrorCode status = U_ZERO_ERROR;
LocalizedNumberFormatter formatter = NumberFormatter::withLocale(Locale::getEnglish());
- const char* str1 = "98765432123456789E1";
- UnicodeString actual = formatter.formatDecimal(str1, status).toString();
+
+ // Double
+ assertEquals("Format double", "514.23", formatter.formatDouble(514.23, status).toString());
+
+ // Int64
+ assertEquals("Format int64", "51,423", formatter.formatDouble(51423L, status).toString());
+
+ // decNumber
+ UnicodeString actual = formatter.formatDecimal("98765432123456789E1", status).toString();
assertEquals("Format decNumber", u"987,654,321,234,567,890", actual);
+
+ // Also test proper DecimalQuantity bytes storage when all digits are in the fraction.
+ // The number needs to have exactly 40 digits, which is the size of the default buffer.
+ // (issue discovered by the address sanitizer in C++)
+ static const char* str = "0.009876543210987654321098765432109876543211";
+ actual = formatter.rounding(Rounder::unlimited()).formatDecimal(str, status).toString();
+ assertEquals("Format decNumber to 40 digits", str, actual);
}
void NumberFormatterApiTest::errors() {
@Override
protected byte getDigitPos(int position) {
if (usingBytes) {
- if (position < 0 || position > precision)
+ if (position < 0 || position >= precision)
return 0;
return bcdBytes[position];
} else {
assertNotEquals(NumberFormatter.with().locale(ULocale.ENGLISH), NumberFormatter.with().locale(Locale.FRENCH));
}
+ @Test
+ public void formatTypes() {
+ LocalizedNumberFormatter formatter = NumberFormatter.withLocale(ULocale.ENGLISH);
+
+ // Double
+ assertEquals("514.23", formatter.format(514.23).toString());
+
+ // Int64
+ assertEquals("51,423", formatter.format(51423L).toString());
+
+ // BigDecimal
+ assertEquals("987,654,321,234,567,890",
+ formatter.format(new BigDecimal("98765432123456789E1")).toString());
+
+ // Also test proper DecimalQuantity bytes storage when all digits are in the fraction.
+ // The number needs to have exactly 40 digits, which is the size of the default buffer.
+ // (issue discovered by the address sanitizer in C++)
+ assertEquals("0.009876543210987654321098765432109876543211",
+ formatter.rounding(Rounder.unlimited())
+ .format(new BigDecimal("0.009876543210987654321098765432109876543211"))
+ .toString());
+ }
+
@Test
public void plurals() {
// TODO: Expand this test.