return fractionCountWithoutTrailingZeros();
case PLURAL_OPERAND_E:
return static_cast<double>(getExponent());
+ case PLURAL_OPERAND_C:
+ // Plural operand `c` is currently an alias for `e`.
+ return static_cast<double>(getExponent());
default:
return std::abs(toDouble());
}
static const UChar PK_VAR_F[]={LOW_F,0};
static const UChar PK_VAR_T[]={LOW_T,0};
static const UChar PK_VAR_E[]={LOW_E,0};
+static const UChar PK_VAR_C[]={LOW_C,0};
static const UChar PK_VAR_V[]={LOW_V,0};
static const UChar PK_WITHIN[]={LOW_W,LOW_I,LOW_T,LOW_H,LOW_I,LOW_N,0};
static const UChar PK_DECIMAL[]={LOW_D,LOW_E,LOW_C,LOW_I,LOW_M,LOW_A,LOW_L,0};
destFd[sampleCount++] = fixed;
}
} else {
-
FixedDecimal fixedLo(sampleRange.tempSubStringBetween(0, tildeIndex), status);
FixedDecimal fixedHi(sampleRange.tempSubStringBetween(tildeIndex+1), status);
double rangeLo = fixedLo.source;
if (rc == nullptr) {
return 0;
}
+
int32_t numSamples = getSamplesFromString(rc->fIntegerSamples, nullptr, dest, destCapacity, status);
if (numSamples == 0) {
numSamples = getSamplesFromString(rc->fDecimalSamples, nullptr, dest, destCapacity, status);
case tVariableF:
case tVariableT:
case tVariableE:
+ case tVariableC:
case tVariableV:
U_ASSERT(curAndConstraint != nullptr);
curAndConstraint->digitsType = type;
s.append(LOW_T); break;
case tVariableE:
s.append(LOW_E); break;
+ case tVariableC:
+ s.append(LOW_C); break;
default:
s.append(TILDE);
}
case tVariableF:
case tVariableT:
case tVariableE:
+ case tVariableC:
case tVariableV:
if (type != tIs && type != tMod && type != tIn &&
type != tNot && type != tWithin && type != tEqual && type != tNotEqual) {
type == tVariableF ||
type == tVariableT ||
type == tVariableE ||
+ type == tVariableC ||
type == tVariableV ||
type == tAt)) {
status = U_UNEXPECTED_TOKEN;
type != tVariableF &&
type != tVariableT &&
type != tVariableE &&
+ type != tVariableC &&
type != tVariableV) {
status = U_UNEXPECTED_TOKEN;
}
keyType = tVariableT;
} else if (0 == token.compare(PK_VAR_E, 1)) {
keyType = tVariableE;
+ } else if (0 == token.compare(PK_VAR_C, 1)) {
+ keyType = tVariableC;
} else if (0 == token.compare(PK_VAR_V, 1)) {
keyType = tVariableV;
} else if (0 == token.compare(PK_IS, 2)) {
return PLURAL_OPERAND_T;
case tVariableE:
return PLURAL_OPERAND_E;
+ case tVariableC:
+ return PLURAL_OPERAND_E;
default:
UPRV_UNREACHABLE; // unexpected.
}
}
+FixedDecimal::FixedDecimal(double n, int32_t v, int64_t f, int32_t e, int32_t c) {
+ init(n, v, f, e, c);
+}
+
FixedDecimal::FixedDecimal(double n, int32_t v, int64_t f, int32_t e) {
init(n, v, f, e);
// check values. TODO make into unit test.
FixedDecimal::FixedDecimal(const UnicodeString &num, UErrorCode &status) {
CharString cs;
int32_t parsedExponent = 0;
+ int32_t parsedCompactExponent = 0;
int32_t exponentIdx = num.indexOf(u'e');
if (exponentIdx < 0) {
exponentIdx = num.indexOf(u'E');
}
+ int32_t compactExponentIdx = num.indexOf(u'c');
+ if (compactExponentIdx < 0) {
+ compactExponentIdx = num.indexOf(u'C');
+ }
+
if (exponentIdx >= 0) {
cs.appendInvariantChars(num.tempSubString(0, exponentIdx), status);
int32_t expSubstrStart = exponentIdx + 1;
parsedExponent = ICU_Utility::parseAsciiInteger(num, expSubstrStart);
}
+ else if (compactExponentIdx >= 0) {
+ cs.appendInvariantChars(num.tempSubString(0, compactExponentIdx), status);
+ int32_t expSubstrStart = compactExponentIdx + 1;
+ parsedCompactExponent = ICU_Utility::parseAsciiInteger(num, expSubstrStart);
+
+ parsedExponent = parsedCompactExponent;
+ exponentIdx = compactExponentIdx;
+ }
else {
cs.appendInvariantChars(num, status);
}
init(n, v, f, exponent);
}
-
void FixedDecimal::init(double n, int32_t v, int64_t f, int32_t e) {
+ // Currently, `c` is an alias for `e`
+ init(n, v, f, e, e);
+}
+
+void FixedDecimal::init(double n, int32_t v, int64_t f, int32_t e, int32_t c) {
isNegative = n < 0.0;
source = fabs(n);
_isNaN = uprv_isNaN(source);
_isInfinite = uprv_isInfinite(source);
exponent = e;
+ if (exponent == 0) {
+ exponent = c;
+ }
if (_isNaN || _isInfinite) {
v = 0;
f = 0;
case PLURAL_OPERAND_T: return static_cast<double>(decimalDigitsWithoutTrailingZeros);
case PLURAL_OPERAND_V: return visibleDecimalDigitCount;
case PLURAL_OPERAND_E: return exponent;
+ case PLURAL_OPERAND_C: return exponent;
default:
UPRV_UNREACHABLE; // unexpected.
}
UnicodeString FixedDecimal::toString() const {
char pattern[15];
char buffer[20];
- if (exponent == 0) {
- snprintf(pattern, sizeof(pattern), "%%.%df", visibleDecimalDigitCount);
- snprintf(buffer, sizeof(buffer), pattern, source);
- } else {
+ if (exponent != 0) {
snprintf(pattern, sizeof(pattern), "%%.%dfe%%d", visibleDecimalDigitCount);
snprintf(buffer, sizeof(buffer), pattern, source, exponent);
+ } else {
+ snprintf(pattern, sizeof(pattern), "%%.%df", visibleDecimalDigitCount);
+ snprintf(buffer, sizeof(buffer), pattern, source);
}
return UnicodeString(buffer, -1, US_INV);
}
tVariableV,
tVariableT,
tVariableE,
+ tVariableC,
tDecimal,
tInteger,
tEOF
PLURAL_OPERAND_W,
/**
- * Suppressed exponent for compact notation (exponent needed in
- * scientific notation with compact notation to approximate i).
+ * Suppressed exponent for scientific notation (exponent needed in
+ * scientific notation to approximate i).
*/
PLURAL_OPERAND_E,
+ /**
+ * This operand is currently treated as an alias for `PLURAL_OPERAND_E`.
+ * In the future, it will represent:
+ *
+ * Suppressed exponent for compact notation (exponent needed in
+ * compact notation to approximate i).
+ */
+ PLURAL_OPERAND_C,
+
/**
* THIS OPERAND IS DEPRECATED AND HAS BEEN REMOVED FROM THE SPEC.
*
* @param n the number, e.g. 12.345
* @param v The number of visible fraction digits, e.g. 3
* @param f The fraction digits, e.g. 345
- * @param e The exponent, e.g. 7 in 1.2e7 (for compact/scientific)
+ * @param e The exponent, e.g. 7 in 1.2e7, for scientific notation
+ * @param c Currently: an alias for param `e`.
*/
+ FixedDecimal(double n, int32_t v, int64_t f, int32_t e, int32_t c);
FixedDecimal(double n, int32_t v, int64_t f, int32_t e);
FixedDecimal(double n, int32_t v, int64_t f);
FixedDecimal(double n, int32_t);
int32_t getVisibleFractionDigitCount() const;
+ void init(double n, int32_t v, int64_t f, int32_t e, int32_t c);
void init(double n, int32_t v, int64_t f, int32_t e);
void init(double n, int32_t v, int64_t f);
void init(double n);
void testToDouble();
void testMaxDigits();
void testNickelRounding();
- void testCompactDecimalSuppressedExponent();
+ void testScientificAndCompactSuppressedExponent();
void testSuppressedExponentUnchangedByInitialScaling();
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
TESTCASE_AUTO(testToDouble);
TESTCASE_AUTO(testMaxDigits);
TESTCASE_AUTO(testNickelRounding);
- TESTCASE_AUTO(testCompactDecimalSuppressedExponent);
+ TESTCASE_AUTO(testScientificAndCompactSuppressedExponent);
TESTCASE_AUTO(testSuppressedExponentUnchangedByInitialScaling);
TESTCASE_AUTO_END;
}
status.expectErrorAndReset(U_FORMAT_INEXACT_ERROR);
}
-void DecimalQuantityTest::testCompactDecimalSuppressedExponent() {
- IcuTestErrorCode status(*this, "testCompactDecimalSuppressedExponent");
+void DecimalQuantityTest::testScientificAndCompactSuppressedExponent() {
+ IcuTestErrorCode status(*this, "testScientificAndCompactSuppressedExponent");
Locale ulocale("fr-FR");
struct TestCase {
int64_t expectedLong;
double expectedDouble;
const char16_t* expectedPlainString;
- int32_t expectedSuppressedExponent;
+ int32_t expectedSuppressedScientificExponent;
+ int32_t expectedSuppressedCompactExponent;
} cases[] = {
- // unlocalized formatter skeleton, input, string output, long output, double output, BigDecimal output, plain string, suppressed exponent
- {u"", 123456789, u"123 456 789", 123456789L, 123456789.0, u"123456789", 0},
- {u"compact-long", 123456789, u"123 millions", 123000000L, 123000000.0, u"123000000", 6},
- {u"compact-short", 123456789, u"123 M", 123000000L, 123000000.0, u"123000000", 6},
- {u"scientific", 123456789, u"1,234568E8", 123456800L, 123456800.0, u"123456800", 8},
-
- {u"", 1234567, u"1 234 567", 1234567L, 1234567.0, u"1234567", 0},
- {u"compact-long", 1234567, u"1,2 million", 1200000L, 1200000.0, u"1200000", 6},
- {u"compact-short", 1234567, u"1,2 M", 1200000L, 1200000.0, u"1200000", 6},
- {u"scientific", 1234567, u"1,234567E6", 1234567L, 1234567.0, u"1234567", 6},
-
- {u"", 123456, u"123 456", 123456L, 123456.0, u"123456", 0},
- {u"compact-long", 123456, u"123 mille", 123000L, 123000.0, u"123000", 3},
- {u"compact-short", 123456, u"123 k", 123000L, 123000.0, u"123000", 3},
- {u"scientific", 123456, u"1,23456E5", 123456L, 123456.0, u"123456", 5},
-
- {u"", 123, u"123", 123L, 123.0, u"123", 0},
- {u"compact-long", 123, u"123", 123L, 123.0, u"123", 0},
- {u"compact-short", 123, u"123", 123L, 123.0, u"123", 0},
- {u"scientific", 123, u"1,23E2", 123L, 123.0, u"123", 2},
-
- {u"", 1.2, u"1,2", 1L, 1.2, u"1.2", 0},
- {u"compact-long", 1.2, u"1,2", 1L, 1.2, u"1.2", 0},
- {u"compact-short", 1.2, u"1,2", 1L, 1.2, u"1.2", 0},
- {u"scientific", 1.2, u"1,2E0", 1L, 1.2, u"1.2", 0},
-
- {u"", 0.12, u"0,12", 0L, 0.12, u"0.12", 0},
- {u"compact-long", 0.12, u"0,12", 0L, 0.12, u"0.12", 0},
- {u"compact-short", 0.12, u"0,12", 0L, 0.12, u"0.12", 0},
- {u"scientific", 0.12, u"1,2E-1", 0L, 0.12, u"0.12", -1},
-
- {u"", 0.012, u"0,012", 0L, 0.012, u"0.012", 0},
- {u"compact-long", 0.012, u"0,012", 0L, 0.012, u"0.012", 0},
- {u"compact-short", 0.012, u"0,012", 0L, 0.012, u"0.012", 0},
- {u"scientific", 0.012, u"1,2E-2", 0L, 0.012, u"0.012", -2},
-
- {u"", 999.9, u"999,9", 999L, 999.9, u"999.9", 0},
- {u"compact-long", 999.9, u"1 millier", 1000L, 1000.0, u"1000", 3},
- {u"compact-short", 999.9, u"1 k", 1000L, 1000.0, u"1000", 3},
- {u"scientific", 999.9, u"9,999E2", 999L, 999.9, u"999.9", 2},
-
- {u"", 1000.0, u"1 000", 1000L, 1000.0, u"1000", 0},
- {u"compact-long", 1000.0, u"1 millier", 1000L, 1000.0, u"1000", 3},
- {u"compact-short", 1000.0, u"1 k", 1000L, 1000.0, u"1000", 3},
- {u"scientific", 1000.0, u"1E3", 1000L, 1000.0, u"1000", 3},
+ // unlocalized formatter skeleton, input, string output, long output,
+ // double output, BigDecimal output, plain string,
+ // suppressed scientific exponent, suppressed compact exponent
+ {u"", 123456789, u"123 456 789", 123456789L, 123456789.0, u"123456789", 0, 0},
+ {u"compact-long", 123456789, u"123 millions", 123000000L, 123000000.0, u"123000000", 6, 6},
+ {u"compact-short", 123456789, u"123 M", 123000000L, 123000000.0, u"123000000", 6, 6},
+ {u"scientific", 123456789, u"1,234568E8", 123456800L, 123456800.0, u"123456800", 8, 8},
+
+ {u"", 1234567, u"1 234 567", 1234567L, 1234567.0, u"1234567", 0, 0},
+ {u"compact-long", 1234567, u"1,2 million", 1200000L, 1200000.0, u"1200000", 6, 6},
+ {u"compact-short", 1234567, u"1,2 M", 1200000L, 1200000.0, u"1200000", 6, 6},
+ {u"scientific", 1234567, u"1,234567E6", 1234567L, 1234567.0, u"1234567", 6, 6},
+
+ {u"", 123456, u"123 456", 123456L, 123456.0, u"123456", 0, 0},
+ {u"compact-long", 123456, u"123 mille", 123000L, 123000.0, u"123000", 3, 3},
+ {u"compact-short", 123456, u"123 k", 123000L, 123000.0, u"123000", 3, 3},
+ {u"scientific", 123456, u"1,23456E5", 123456L, 123456.0, u"123456", 5, 5},
+
+ {u"", 123, u"123", 123L, 123.0, u"123", 0, 0},
+ {u"compact-long", 123, u"123", 123L, 123.0, u"123", 0, 0},
+ {u"compact-short", 123, u"123", 123L, 123.0, u"123", 0, 0},
+ {u"scientific", 123, u"1,23E2", 123L, 123.0, u"123", 2, 2},
+
+ {u"", 1.2, u"1,2", 1L, 1.2, u"1.2", 0, 0},
+ {u"compact-long", 1.2, u"1,2", 1L, 1.2, u"1.2", 0, 0},
+ {u"compact-short", 1.2, u"1,2", 1L, 1.2, u"1.2", 0, 0},
+ {u"scientific", 1.2, u"1,2E0", 1L, 1.2, u"1.2", 0, 0},
+
+ {u"", 0.12, u"0,12", 0L, 0.12, u"0.12", 0, 0},
+ {u"compact-long", 0.12, u"0,12", 0L, 0.12, u"0.12", 0, 0},
+ {u"compact-short", 0.12, u"0,12", 0L, 0.12, u"0.12", 0, 0},
+ {u"scientific", 0.12, u"1,2E-1", 0L, 0.12, u"0.12", -1, -1},
+
+ {u"", 0.012, u"0,012", 0L, 0.012, u"0.012", 0, 0},
+ {u"compact-long", 0.012, u"0,012", 0L, 0.012, u"0.012", 0, 0},
+ {u"compact-short", 0.012, u"0,012", 0L, 0.012, u"0.012", 0, 0},
+ {u"scientific", 0.012, u"1,2E-2", 0L, 0.012, u"0.012", -2, -2},
+
+ {u"", 999.9, u"999,9", 999L, 999.9, u"999.9", 0, 0},
+ {u"compact-long", 999.9, u"1 millier", 1000L, 1000.0, u"1000", 3, 3},
+ {u"compact-short", 999.9, u"1 k", 1000L, 1000.0, u"1000", 3, 3},
+ {u"scientific", 999.9, u"9,999E2", 999L, 999.9, u"999.9", 2, 2},
+
+ {u"", 1000.0, u"1 000", 1000L, 1000.0, u"1000", 0, 0},
+ {u"compact-long", 1000.0, u"1 millier", 1000L, 1000.0, u"1000", 3, 3},
+ {u"compact-short", 1000.0, u"1 k", 1000L, 1000.0, u"1000", 3, 3},
+ {u"scientific", 1000.0, u"1E3", 1000L, 1000.0, u"1000", 3, 3},
};
for (const auto& cas : cases) {
// test the helper methods used to compute plural operand values
int64_t actualLong = dq.toLong();
double actualDouble = dq.toDouble();
UnicodeString actualPlainString = dq.toPlainString();
- int32_t actualSuppressedExponent = dq.getExponent();
+ int32_t actualSuppressedScientificExponent = dq.getExponent();
+ int32_t actualSuppressedCompactExponent = dq.getExponent();
assertEquals(
u"formatted number " + cas.skeleton + u" toString: " + cas.input,
cas.expectedString,
actualString);
assertEquals(
- u"compact decimal " + cas.skeleton + u" toLong: " + cas.input,
+ u"formatted number " + cas.skeleton + u" toLong: " + cas.input,
cas.expectedLong,
actualLong);
assertDoubleEquals(
- u"compact decimal " + cas.skeleton + u" toDouble: " + cas.input,
+ u"formatted number " + cas.skeleton + u" toDouble: " + cas.input,
cas.expectedDouble,
actualDouble);
assertEquals(
cas.expectedPlainString,
actualPlainString);
assertEquals(
- u"compact decimal " + cas.skeleton + u" suppressed exponent: " + cas.input,
- cas.expectedSuppressedExponent,
- actualSuppressedExponent);
+ u"formatted number " + cas.skeleton + u" suppressed scientific exponent: " + cas.input,
+ cas.expectedSuppressedScientificExponent,
+ actualSuppressedScientificExponent);
+ assertEquals(
+ u"formatted number " + cas.skeleton + u" suppressed compact exponent: " + cas.input,
+ cas.expectedSuppressedCompactExponent,
+ actualSuppressedCompactExponent);
// test the actual computed values of the plural operands
double expectedNOperand = cas.expectedDouble;
double expectedIOperand = cas.expectedLong;
- double expectedEOperand = cas.expectedSuppressedExponent;
+ double expectedEOperand = cas.expectedSuppressedScientificExponent;
+ double expectedCOperand = cas.expectedSuppressedCompactExponent;
double actualNOperand = dq.getPluralOperand(PLURAL_OPERAND_N);
double actualIOperand = dq.getPluralOperand(PLURAL_OPERAND_I);
double actualEOperand = dq.getPluralOperand(PLURAL_OPERAND_E);
+ double actualCOperand = dq.getPluralOperand(PLURAL_OPERAND_C);
assertDoubleEquals(
- u"compact decimal " + cas.skeleton + u" n operand: " + cas.input,
+ u"formatted number " + cas.skeleton + u" n operand: " + cas.input,
expectedNOperand,
actualNOperand);
assertDoubleEquals(
- u"compact decimal " + cas.skeleton + u" i operand: " + cas.input,
+ u"formatted number " + cas.skeleton + u" i operand: " + cas.input,
expectedIOperand,
actualIOperand);
assertDoubleEquals(
- u"compact decimal " + cas.skeleton + " e operand: " + cas.input,
+ u"formatted number " + cas.skeleton + " e operand: " + cas.input,
expectedEOperand,
actualEOperand);
+ assertDoubleEquals(
+ u"formatted number " + cas.skeleton + " c operand: " + cas.input,
+ expectedCOperand,
+ actualCOperand);
}
}
void DecimalQuantityTest::testSuppressedExponentUnchangedByInitialScaling() {
- IcuTestErrorCode status(*this, "testCompactDecimalSuppressedExponent");
+ IcuTestErrorCode status(*this, "testSuppressedExponentUnchangedByInitialScaling");
Locale ulocale("fr-FR");
LocalizedNumberFormatter withLocale = NumberFormatter::withLocale(ulocale);
LocalizedNumberFormatter compactLong =
double expectedNOperand;
double expectedIOperand;
double expectedEOperand;
+ double expectedCOperand;
} cases[] = {
// input, compact long string output,
- // compact n operand, compact i operand, compact e operand
- {123456789, "123 millions", 123000000.0, 123000000.0, 6.0},
- {1234567, "1,2 million", 1200000.0, 1200000.0, 6.0},
- {123456, "123 mille", 123000.0, 123000.0, 3.0},
- {123, "123", 123.0, 123.0, 0.0},
+ // compact n operand, compact i operand, compact e operand,
+ // compact c operand
+ {123456789, "123 millions", 123000000.0, 123000000.0, 6.0, 6.0},
+ {1234567, "1,2 million", 1200000.0, 1200000.0, 6.0, 6.0},
+ {123456, "123 mille", 123000.0, 123000.0, 3.0, 3.0},
+ {123, "123", 123.0, 123.0, 0.0, 0.0},
};
for (const auto& cas : cases) {
FormattedNumber fnCompactScaled = compactScaled.formatInt(cas.input, status);
DecimalQuantity dqCompactScaled;
fnCompactScaled.getDecimalQuantity(dqCompactScaled, status);
- double compactScaledEOperand = dqCompactScaled.getPluralOperand(PLURAL_OPERAND_E);
+ double compactScaledCOperand = dqCompactScaled.getPluralOperand(PLURAL_OPERAND_C);
FormattedNumber fnCompact = compactLong.formatInt(cas.input, status);
DecimalQuantity dqCompact;
double compactNOperand = dqCompact.getPluralOperand(PLURAL_OPERAND_N);
double compactIOperand = dqCompact.getPluralOperand(PLURAL_OPERAND_I);
double compactEOperand = dqCompact.getPluralOperand(PLURAL_OPERAND_E);
+ double compactCOperand = dqCompact.getPluralOperand(PLURAL_OPERAND_C);
assertEquals(
u"formatted number " + Int64ToUnicodeString(cas.input) + " compactLong toString: ",
cas.expectedString,
u"compact decimal " + DoubleToUnicodeString(cas.input) + ", e operand vs. expected",
cas.expectedEOperand,
compactEOperand);
+ assertDoubleEquals(
+ u"compact decimal " + DoubleToUnicodeString(cas.input) + ", c operand vs. expected",
+ cas.expectedCOperand,
+ compactCOperand);
// By scaling by 10^3 in a locale that has words / compact notation
// based on powers of 10^3, we guarantee that the suppressed
// exponent will differ by 3.
assertDoubleEquals(
- u"decimal " + DoubleToUnicodeString(cas.input) + ", e operand for compact vs. compact scaled",
- compactEOperand + 3,
- compactScaledEOperand);
+ u"decimal " + DoubleToUnicodeString(cas.input) + ", c operand for compact vs. compact scaled",
+ compactCOperand + 3,
+ compactScaledCOperand);
}
}
TESTCASE_AUTO(testGetSamples);
TESTCASE_AUTO(testGetFixedDecimalSamples);
TESTCASE_AUTO(testSamplesWithExponent);
+ TESTCASE_AUTO(testSamplesWithCompactNotation);
TESTCASE_AUTO(testWithin);
TESTCASE_AUTO(testGetAllKeywordValues);
+ TESTCASE_AUTO(testScientificPluralKeyword);
TESTCASE_AUTO(testCompactDecimalPluralKeyword);
TESTCASE_AUTO(testOrdinal);
TESTCASE_AUTO(testSelect);
double values[1000];
for (int32_t i = 0; U_SUCCESS(status) && i < numLocales; ++i) {
if (uprv_strcmp(locales[i].getLanguage(), "fr") == 0 &&
- logKnownIssue("21299", "PluralRules::getSamples cannot distinguish 1e5 from 100000")) {
+ logKnownIssue("21322", "PluralRules::getSamples cannot distinguish 1e5 from 100000")) {
continue;
}
LocalPointer<PluralRules> rules(PluralRules::forLocale(locales[i], status));
FixedDecimal values[1000];
for (int32_t i = 0; U_SUCCESS(status) && i < numLocales; ++i) {
if (uprv_strcmp(locales[i].getLanguage(), "fr") == 0 &&
- logKnownIssue("21299", "PluralRules::getSamples cannot distinguish 1e5 from 100000")) {
+ logKnownIssue("21322", "PluralRules::getSamples cannot distinguish 1e5 from 100000")) {
continue;
}
LocalPointer<PluralRules> rules(PluralRules::forLocale(locales[i], status));
checkNewSamples(description2, test2, u"other", u"@decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 2.1e5, 3.1e5, 4.1e5, 5.1e5, 6.1e5, 7.1e5, …", FixedDecimal(2.0, 1));
}
+
+void PluralRulesTest::testSamplesWithCompactNotation() {
+ // integer samples
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString description(
+ u"one: i = 0,1 @integer 0, 1, 1c5 @decimal 0.0~1.5, 1.1c5; "
+ u"many: c = 0 and i != 0 and i % 1000000 = 0 and v = 0 or c != 0..5"
+ u" @integer 1000000, 2c6, 3c6, 4c6, 5c6, 6c6, 7c6, … @decimal 2.1c6, 3.1c6, 4.1c6, 5.1c6, 6.1c6, 7.1c6, …; "
+ u"other: @integer 2~17, 100, 1000, 10000, 100000, 2c5, 3c5, 4c5, 5c5, 6c5, 7c5, …"
+ u" @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 2.1c5, 3.1c5, 4.1c5, 5.1c5, 6.1c5, 7.1c5, …"
+ );
+ LocalPointer<PluralRules> test(PluralRules::createRules(description, status));
+ if (U_FAILURE(status)) {
+ errln("Couldn't create plural rules from a string using exponent notation, with error = %s", u_errorName(status));
+ return;
+ }
+ checkNewSamples(description, test, u"one", u"@integer 0, 1, 1c5", FixedDecimal(0));
+ checkNewSamples(description, test, u"many", u"@integer 1000000, 2c6, 3c6, 4c6, 5c6, 6c6, 7c6, …", FixedDecimal(1000000));
+ checkNewSamples(description, test, u"other", u"@integer 2~17, 100, 1000, 10000, 100000, 2c5, 3c5, 4c5, 5c5, 6c5, 7c5, …", FixedDecimal(2));
+
+ // decimal samples
+ status = U_ZERO_ERROR;
+ UnicodeString description2(
+ u"one: i = 0,1 @decimal 0.0~1.5, 1.1c5; "
+ u"many: c = 0 and i != 0 and i % 1000000 = 0 and v = 0 or c != 0..5"
+ u" @decimal 2.1c6, 3.1c6, 4.1c6, 5.1c6, 6.1c6, 7.1c6, …; "
+ u"other: @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 2.1c5, 3.1c5, 4.1c5, 5.1c5, 6.1c5, 7.1c5, …"
+ );
+ LocalPointer<PluralRules> test2(PluralRules::createRules(description2, status));
+ if (U_FAILURE(status)) {
+ errln("Couldn't create plural rules from a string using exponent notation, with error = %s", u_errorName(status));
+ return;
+ }
+ checkNewSamples(description2, test2, u"one", u"@decimal 0.0~1.5, 1.1c5", FixedDecimal(0, 1));
+ checkNewSamples(description2, test2, u"many", u"@decimal 2.1c6, 3.1c6, 4.1c6, 5.1c6, 6.1c6, 7.1c6, …", FixedDecimal::createWithExponent(2.1, 1, 6));
+ checkNewSamples(description2, test2, u"other", u"@decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 2.1c5, 3.1c5, 4.1c5, 5.1c5, 6.1c5, 7.1c5, …", FixedDecimal(2.0, 1));
+}
+
void PluralRulesTest::checkNewSamples(
UnicodeString description,
const LocalPointer<PluralRules> &test,
}
}
+// For the time being, the compact notation exponent operand `c` is an alias
+// for the scientific exponent operand `e` and compact notation.
+void
+PluralRulesTest::testScientificPluralKeyword() {
+ IcuTestErrorCode errorCode(*this, "testScientificPluralKeyword");
+
+ LocalPointer<PluralRules> rules(PluralRules::createRules(
+ u"one: i = 0,1 @integer 0, 1 @decimal 0.0~1.5; "
+ u"many: e = 0 and i % 1000000 = 0 and v = 0 or e != 0 .. 5; "
+ u"other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, "
+ u" @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …", errorCode));
+
+ if (U_FAILURE(errorCode)) {
+ errln("Couldn't instantiate plurals rules from string, with error = %s", u_errorName(errorCode));
+ return;
+ }
+
+ const char* localeName = "fr-FR";
+ Locale locale = Locale::createFromName(localeName);
+
+ struct TestCase {
+ const char16_t* skeleton;
+ const int input;
+ const char16_t* expectedFormattedOutput;
+ const char16_t* expectedPluralRuleKeyword;
+ } cases[] = {
+ // unlocalized formatter skeleton, input, string output, plural rule keyword
+ {u"", 0, u"0", u"one"},
+ {u"scientific", 0, u"0", u"one"},
+
+ {u"", 1, u"1", u"one"},
+ {u"scientific", 1, u"1", u"one"},
+
+ {u"", 2, u"2", u"other"},
+ {u"scientific", 2, u"2", u"other"},
+
+ {u"", 1000000, u"1 000 000", u"many"},
+ {u"scientific", 1000000, u"1 million", u"many"},
+
+ {u"", 1000001, u"1 000 001", u"other"},
+ {u"scientific", 1000001, u"1 million", u"many"},
+
+ {u"", 120000, u"1 200 000", u"other"},
+ {u"scientific", 1200000, u"1,2 millions", u"many"},
+
+ {u"", 1200001, u"1 200 001", u"other"},
+ {u"scientific", 1200001, u"1,2 millions", u"many"},
+
+ {u"", 2000000, u"2 000 000", u"many"},
+ {u"scientific", 2000000, u"2 millions", u"many"},
+ };
+ for (const auto& cas : cases) {
+ const char16_t* skeleton = cas.skeleton;
+ const int input = cas.input;
+ const char16_t* expectedPluralRuleKeyword = cas.expectedPluralRuleKeyword;
+
+ UnicodeString actualPluralRuleKeyword =
+ getPluralKeyword(rules, locale, input, skeleton);
+
+ UnicodeString message(UnicodeString(localeName) + u" " + DoubleToUnicodeString(input));
+ assertEquals(message, expectedPluralRuleKeyword, actualPluralRuleKeyword);
+ }
+}
+
void
PluralRulesTest::testCompactDecimalPluralKeyword() {
IcuTestErrorCode errorCode(*this, "testCompactDecimalPluralKeyword");
LocalPointer<PluralRules> rules(PluralRules::createRules(
u"one: i = 0,1 @integer 0, 1 @decimal 0.0~1.5; "
- u"many: e = 0 and i % 1000000 = 0 and v = 0 or e != 0 .. 5; "
+ u"many: c = 0 and i % 1000000 = 0 and v = 0 or c != 0 .. 5; "
u"other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, "
u" @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …", errorCode));
void testGetSamples();
void testGetFixedDecimalSamples();
void testSamplesWithExponent();
+ void testSamplesWithCompactNotation();
void testWithin();
void testGetAllKeywordValues();
void testCompactDecimalPluralKeyword();
+ void testScientificPluralKeyword();
void testOrdinal();
void testSelect();
void testSelectRange();
return fractionCountWithoutTrailingZeros();
case e:
return getExponent();
+ case c:
+ // Plural operand `c` is currently an alias for `e`.
+ return getExponent();
default:
return Math.abs(toDouble());
}
w,
/**
- * Suppressed exponent for compact notation (exponent needed in
- * scientific notation with compact notation to approximate i).
+ * Suppressed exponent for scientific notation (exponent needed in
+ * scientific notation to approximate i).
*
* @internal
* @deprecated This API is ICU internal only.
@Deprecated
e,
+ /**
+ * This operand is currently treated as an alias for `PLURAL_OPERAND_E`.
+ * In the future, it will represent:
+ *
+ * Suppressed exponent for compact notation (exponent needed in
+ * compact notation to approximate i).
+ *
+ * @internal
+ * @deprecated This API is ICU internal only.
+ */
+ @Deprecated
+ c,
+
/**
* THIS OPERAND IS DEPRECATED AND HAS BEEN REMOVED FROM THE SPEC.
*
* @param v number of digits to the right of the decimal place. e.g 1.00 = 2 25. = 0
* @param f Corresponds to f in the plural rules grammar.
* The digits to the right of the decimal place as an integer. e.g 1.10 = 10
- * @param e Suppressed exponent for scientific and compact notation
+ * @param e Suppressed exponent for scientific notation
+ * @param c Currently: an alias for param `e`
*/
@Deprecated
- public FixedDecimal(double n, int v, long f, int e) {
+ public FixedDecimal(double n, int v, long f, int e, int c) {
isNegative = n < 0;
source = isNegative ? -n : n;
visibleDecimalDigitCount = v;
integerValue = n > MAX
? MAX
: (long)n;
- exponent = e;
+ int initExpVal = e;
+ if (initExpVal == 0) {
+ initExpVal = c;
+ }
+ exponent = initExpVal;
hasIntegerValue = source == integerValue;
// check values. TODO make into unit test.
//
baseFactor = (int) Math.pow(10, v);
}
+ /**
+ * @internal CLDR
+ * @deprecated This API is ICU internal only.
+ */
+ @Deprecated
+ public FixedDecimal(double n, int v, long f, int e) {
+ this(n, v, f, e, e);
+ }
+
/**
* @internal CLDR
* @deprecated This API is ICU internal only.
*/
@Deprecated
private static FixedDecimal parseDecimalSampleRangeNumString(String num) {
- if (num.contains("e")) {
+ if (num.contains("e") || num.contains("c")) {
int ePos = num.lastIndexOf('e');
+ if (ePos < 0) {
+ ePos = num.lastIndexOf('c');
+ }
int expNumPos = ePos + 1;
String exponentStr = num.substring(expNumPos);
int exponent = Integer.parseInt(exponentStr);
case v: return visibleDecimalDigitCount;
case w: return visibleDecimalDigitCountWithoutTrailingZeros;
case e: return exponent;
+ case c: return exponent;
default: return source;
}
}
@Override
public String toString() {
String baseString = String.format(Locale.ROOT, "%." + visibleDecimalDigitCount + "f", source);
- if (exponent == 0) {
- return baseString;
- } else {
+ if (exponent != 0) {
return baseString + "e" + exponent;
+ } else {
+ return baseString;
}
}
new FixedDecimal(2.0, 1));
}
+ /**
+ * This test is for the support of X.YcZ compactnotation of numbers in
+ * the plural sample string.
+ */
+ @Test
+ public void testSamplesWithCompactNotation() {
+ String description = "one: i = 0,1 @integer 0, 1, 1c5 @decimal 0.0~1.5, 1.1c5; "
+ + "many: c = 0 and i != 0 and i % 1000000 = 0 and v = 0 or c != 0..5"
+ + " @integer 1000000, 2c6, 3c6, 4c6, 5c6, 6c6, 7c6, … @decimal 2.1c6, 3.1c6, 4.1c6, 5.1c6, 6.1c6, 7.1c6, …; "
+ + "other: @integer 2~17, 100, 1000, 10000, 100000, 2c5, 3c5, 4c5, 5c5, 6c5, 7c5, …"
+ + " @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 2.1c5, 3.1c5, 4.1c5, 5.1c5, 6.1c5, 7.1c5, …"
+ ;
+ // Creating the PluralRules object means being able to parse numbers
+ // like 1c5 and 1.1c5.
+ // Note: Since `c` is currently an alias to `e`, the toString() of
+ // FixedDecimal will return "1e5" even when input is "1c5".
+ PluralRules test = PluralRules.createRules(description);
+ checkNewSamples(description, test, "one", PluralRules.SampleType.INTEGER, "@integer 0, 1, 1e5", true,
+ new FixedDecimal(0));
+ checkNewSamples(description, test, "one", PluralRules.SampleType.DECIMAL, "@decimal 0.0~1.5, 1.1e5", true,
+ new FixedDecimal(0, 1));
+ checkNewSamples(description, test, "many", PluralRules.SampleType.INTEGER, "@integer 1000000, 2e6, 3e6, 4e6, 5e6, 6e6, 7e6, …", false,
+ new FixedDecimal(1000000));
+ checkNewSamples(description, test, "many", PluralRules.SampleType.DECIMAL, "@decimal 2.1e6, 3.1e6, 4.1e6, 5.1e6, 6.1e6, 7.1e6, …", false,
+ FixedDecimal.createWithExponent(2.1, 1, 6));
+ checkNewSamples(description, test, "other", PluralRules.SampleType.INTEGER, "@integer 2~17, 100, 1000, 10000, 100000, 2e5, 3e5, 4e5, 5e5, 6e5, 7e5, …", false,
+ new FixedDecimal(2));
+ checkNewSamples(description, test, "other", PluralRules.SampleType.DECIMAL, "@decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 2.1e5, 3.1e5, 4.1e5, 5.1e5, 6.1e5, 7.1e5, …", false,
+ new FixedDecimal(2.0, 1));
+ }
+
public void checkOldSamples(String description, PluralRules rules, String keyword, SampleType sampleType,
Double... expected) {
Collection<Double> oldSamples = rules.getSamples(keyword, sampleType);
}
for (ULocale locale : uniqueRuleSet) {
if (locale.getLanguage().equals("fr") &&
- logKnownIssue("21299", "PluralRules::getSamples cannot distinguish 1e5 from 100000")) {
+ logKnownIssue("21322", "PluralRules::getSamples cannot distinguish 1e5 from 100000")) {
continue;
}
PluralRules rules = factory.forLocale(locale);
}
}
+ // For the time being, the compact notation exponent operand `c` is an alias
+ // for the scientific exponent operand `e` and compact notation.
+ @Test
+ public void testScientificPluralKeyword() {
+ PluralRules rules = PluralRules.createRules("one: i = 0,1 @integer 0, 1 @decimal 0.0~1.5; many: e = 0 and i % 1000000 = 0 and v = 0 or " +
+ "e != 0 .. 5; other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …");
+ ULocale locale = new ULocale("fr-FR");
+ Object[][] casesData = {
+ // unlocalized formatter skeleton, input, string output, plural rule keyword
+ {"", 0, "0", "one"},
+ {"scientific", 0, "0", "one"},
+
+ {"", 1, "1", "one"},
+ {"scientific", 1, "1", "one"},
+
+ {"", 2, "2", "other"},
+ {"scientific", 2, "2", "other"},
+
+ {"", 1000000, "1 000 000", "many"},
+ {"scientific", 1000000, "1 million", "many"},
+
+ {"", 1000001, "1 000 001", "other"},
+ {"scientific", 1000001, "1 million", "many"},
+
+ {"", 120000, "1 200 000", "other"},
+ {"scientific", 1200000, "1,2 millions", "many"},
+
+ {"", 1200001, "1 200 001", "other"},
+ {"scientific", 1200001, "1,2 millions", "many"},
+
+ {"", 2000000, "2 000 000", "many"},
+ {"scientific", 2000000, "2 millions", "many"},
+ };
+
+ for (Object[] caseDatum : casesData) {
+ String skeleton = (String) caseDatum[0];
+ int input = (int) caseDatum[1];
+ // String expectedString = (String) caseDatum[2];
+ String expectPluralRuleKeyword = (String) caseDatum[3];
+
+ String actualPluralRuleKeyword =
+ getPluralKeyword(rules, locale, input, skeleton);
+
+ assertEquals(
+ String.format("PluralRules select %s: %d", skeleton, input),
+ expectPluralRuleKeyword,
+ actualPluralRuleKeyword);
+ }
+ }
@Test
public void testCompactDecimalPluralKeyword() {
- PluralRules rules = PluralRules.createRules("one: i = 0,1 @integer 0, 1 @decimal 0.0~1.5; many: e = 0 and i % 1000000 = 0 and v = 0 or " +
- "e != 0 .. 5; other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …");
+ PluralRules rules = PluralRules.createRules("one: i = 0,1 @integer 0, 1 @decimal 0.0~1.5; many: c = 0 and i % 1000000 = 0 and v = 0 or " +
+ "c != 0 .. 5; other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …");
ULocale locale = new ULocale("fr-FR");
Object[][] casesData = {
}
@Test
- public void testCompactDecimalSuppressedExponent() {
+ public void testScientificAndCompactSuppressedExponent() {
ULocale locale = new ULocale("fr-FR");
Object[][] casesData = {
- // unlocalized formatter skeleton, input, string output, long output, double output, BigDecimal output, plain string, suppressed exponent
- {"", 123456789, "123 456 789", 123456789L, 123456789.0, new BigDecimal("123456789"), "123456789", 0},
- {"compact-long", 123456789, "123 millions", 123000000L, 123000000.0, new BigDecimal("123000000"), "123000000", 6},
- {"compact-short", 123456789, "123 M", 123000000L, 123000000.0, new BigDecimal("123000000"), "123000000", 6},
- {"scientific", 123456789, "1,234568E8", 123456800L, 123456800.0, new BigDecimal("123456800"), "123456800", 8},
-
- {"", 1234567, "1 234 567", 1234567L, 1234567.0, new BigDecimal("1234567"), "1234567", 0},
- {"compact-long", 1234567, "1,2 million", 1200000L, 1200000.0, new BigDecimal("1200000"), "1200000", 6},
- {"compact-short", 1234567, "1,2 M", 1200000L, 1200000.0, new BigDecimal("1200000"), "1200000", 6},
- {"scientific", 1234567, "1,234567E6", 1234567L, 1234567.0, new BigDecimal("1234567"), "1234567", 6},
-
- {"", 123456, "123 456", 123456L, 123456.0, new BigDecimal("123456"), "123456", 0},
- {"compact-long", 123456, "123 mille", 123000L, 123000.0, new BigDecimal("123000"), "123000", 3},
- {"compact-short", 123456, "123 k", 123000L, 123000.0, new BigDecimal("123000"), "123000", 3},
- {"scientific", 123456, "1,23456E5", 123456L, 123456.0, new BigDecimal("123456"), "123456", 5},
-
- {"", 123, "123", 123L, 123.0, new BigDecimal("123"), "123", 0},
- {"compact-long", 123, "123", 123L, 123.0, new BigDecimal("123"), "123", 0},
- {"compact-short", 123, "123", 123L, 123.0, new BigDecimal("123"), "123", 0},
- {"scientific", 123, "1,23E2", 123L, 123.0, new BigDecimal("123"), "123", 2},
-
- {"", 1.2, "1,2", 1L, 1.2, new BigDecimal("1.2"), "1.2", 0},
- {"compact-long", 1.2, "1,2", 1L, 1.2, new BigDecimal("1.2"), "1.2", 0},
- {"compact-short", 1.2, "1,2", 1L, 1.2, new BigDecimal("1.2"), "1.2", 0},
- {"scientific", 1.2, "1,2E0", 1L, 1.2, new BigDecimal("1.2"), "1.2", 0},
-
- {"", 0.12, "0,12", 0L, 0.12, new BigDecimal("0.12"), "0.12", 0},
- {"compact-long", 0.12, "0,12", 0L, 0.12, new BigDecimal("0.12"), "0.12", 0},
- {"compact-short", 0.12, "0,12", 0L, 0.12, new BigDecimal("0.12"), "0.12", 0},
- {"scientific", 0.12, "1,2E-1", 0L, 0.12, new BigDecimal("0.12"), "0.12", -1},
-
- {"", 0.012, "0,012", 0L, 0.012, new BigDecimal("0.012"), "0.012", 0},
- {"compact-long", 0.012, "0,012", 0L, 0.012, new BigDecimal("0.012"), "0.012", 0},
- {"compact-short", 0.012, "0,012", 0L, 0.012, new BigDecimal("0.012"), "0.012", 0},
- {"scientific", 0.012, "1,2E-2", 0L, 0.012, new BigDecimal("0.012"), "0.012", -2},
-
- {"", 999.9, "999,9", 999L, 999.9, new BigDecimal("999.9"), "999.9", 0},
- {"compact-long", 999.9, "1 millier", 1000L, 1000.0, new BigDecimal("1000"), "1000", 3},
- {"compact-short", 999.9, "1 k", 1000L, 1000.0, new BigDecimal("1000"), "1000", 3},
- {"scientific", 999.9, "9,999E2", 999L, 999.9, new BigDecimal("999.9"), "999.9", 2},
-
- {"", 1000.0, "1 000", 1000L, 1000.0, new BigDecimal("1000"), "1000", 0},
- {"compact-long", 1000.0, "1 millier", 1000L, 1000.0, new BigDecimal("1000"), "1000", 3},
- {"compact-short", 1000.0, "1 k", 1000L, 1000.0, new BigDecimal("1000"), "1000", 3},
- {"scientific", 1000.0, "1E3", 1000L, 1000.0, new BigDecimal("1000"), "1000", 3},
+ // unlocalized formatter skeleton, input, string output, long output,
+ // double output, BigDecimal output, plain string,
+ // suppressed scientific exponent, suppressed compact exponent
+ {"", 123456789, "123 456 789", 123456789L, 123456789.0, new BigDecimal("123456789"), "123456789", 0, 0},
+ {"compact-long", 123456789, "123 millions", 123000000L, 123000000.0, new BigDecimal("123000000"), "123000000", 6, 6},
+ {"compact-short", 123456789, "123 M", 123000000L, 123000000.0, new BigDecimal("123000000"), "123000000", 6, 6},
+ {"scientific", 123456789, "1,234568E8", 123456800L, 123456800.0, new BigDecimal("123456800"), "123456800", 8, 8},
+
+ {"", 1234567, "1 234 567", 1234567L, 1234567.0, new BigDecimal("1234567"), "1234567", 0, 0},
+ {"compact-long", 1234567, "1,2 million", 1200000L, 1200000.0, new BigDecimal("1200000"), "1200000", 6, 6},
+ {"compact-short", 1234567, "1,2 M", 1200000L, 1200000.0, new BigDecimal("1200000"), "1200000", 6, 6},
+ {"scientific", 1234567, "1,234567E6", 1234567L, 1234567.0, new BigDecimal("1234567"), "1234567", 6, 6},
+
+ {"", 123456, "123 456", 123456L, 123456.0, new BigDecimal("123456"), "123456", 0, 0},
+ {"compact-long", 123456, "123 mille", 123000L, 123000.0, new BigDecimal("123000"), "123000", 3, 3},
+ {"compact-short", 123456, "123 k", 123000L, 123000.0, new BigDecimal("123000"), "123000", 3, 3},
+ {"scientific", 123456, "1,23456E5", 123456L, 123456.0, new BigDecimal("123456"), "123456", 5, 5},
+
+ {"", 123, "123", 123L, 123.0, new BigDecimal("123"), "123", 0, 0},
+ {"compact-long", 123, "123", 123L, 123.0, new BigDecimal("123"), "123", 0, 0},
+ {"compact-short", 123, "123", 123L, 123.0, new BigDecimal("123"), "123", 0, 0},
+ {"scientific", 123, "1,23E2", 123L, 123.0, new BigDecimal("123"), "123", 2, 2},
+
+ {"", 1.2, "1,2", 1L, 1.2, new BigDecimal("1.2"), "1.2", 0, 0},
+ {"compact-long", 1.2, "1,2", 1L, 1.2, new BigDecimal("1.2"), "1.2", 0, 0},
+ {"compact-short", 1.2, "1,2", 1L, 1.2, new BigDecimal("1.2"), "1.2", 0, 0},
+ {"scientific", 1.2, "1,2E0", 1L, 1.2, new BigDecimal("1.2"), "1.2", 0, 0},
+
+ {"", 0.12, "0,12", 0L, 0.12, new BigDecimal("0.12"), "0.12", 0, 0},
+ {"compact-long", 0.12, "0,12", 0L, 0.12, new BigDecimal("0.12"), "0.12", 0, 0},
+ {"compact-short", 0.12, "0,12", 0L, 0.12, new BigDecimal("0.12"), "0.12", 0, 0},
+ {"scientific", 0.12, "1,2E-1", 0L, 0.12, new BigDecimal("0.12"), "0.12", -1, -1},
+
+ {"", 0.012, "0,012", 0L, 0.012, new BigDecimal("0.012"), "0.012", 0, 0},
+ {"compact-long", 0.012, "0,012", 0L, 0.012, new BigDecimal("0.012"), "0.012", 0, 0},
+ {"compact-short", 0.012, "0,012", 0L, 0.012, new BigDecimal("0.012"), "0.012", 0, 0},
+ {"scientific", 0.012, "1,2E-2", 0L, 0.012, new BigDecimal("0.012"), "0.012", -2, -2},
+
+ {"", 999.9, "999,9", 999L, 999.9, new BigDecimal("999.9"), "999.9", 0, 0},
+ {"compact-long", 999.9, "1 millier", 1000L, 1000.0, new BigDecimal("1000"), "1000", 3, 3},
+ {"compact-short", 999.9, "1 k", 1000L, 1000.0, new BigDecimal("1000"), "1000", 3, 3},
+ {"scientific", 999.9, "9,999E2", 999L, 999.9, new BigDecimal("999.9"), "999.9", 2, 2},
+
+ {"", 1000.0, "1 000", 1000L, 1000.0, new BigDecimal("1000"), "1000", 0, 0},
+ {"compact-long", 1000.0, "1 millier", 1000L, 1000.0, new BigDecimal("1000"), "1000", 3, 3},
+ {"compact-short", 1000.0, "1 k", 1000L, 1000.0, new BigDecimal("1000"), "1000", 3, 3},
+ {"scientific", 1000.0, "1E3", 1000L, 1000.0, new BigDecimal("1000"), "1000", 3, 3},
};
for (Object[] caseDatum : casesData) {
double expectedDouble = (double) caseDatum[4];
BigDecimal expectedBigDecimal = (BigDecimal) caseDatum[5];
String expectedPlainString = (String) caseDatum[6];
- int expectedSuppressedExponent = (int) caseDatum[7];
+ int expectedSuppressedScientificExponent = (int) caseDatum[7];
+ int expectedSuppressedCompactExponent = (int) caseDatum[8];
FormattedNumber fn = formatter.format(input);
DecimalQuantity_DualStorageBCD dq = (DecimalQuantity_DualStorageBCD)
double actualDouble = dq.toDouble();
BigDecimal actualBigDecimal = dq.toBigDecimal();
String actualPlainString = dq.toPlainString();
- int actualSuppressedExponent = dq.getExponent();
+ int actualSuppressedScientificExponent = dq.getExponent();
+ int actualSuppressedCompactExponent = dq.getExponent();
assertEquals(
String.format("formatted number %s toString: %f", skeleton, input),
expectedString,
actualString);
assertEquals(
- String.format("compact decimal %s toLong: %f", skeleton, input),
+ String.format("formatted number %s toLong: %f", skeleton, input),
expectedLong,
actualLong);
assertDoubleEquals(
- String.format("compact decimal %s toDouble: %f", skeleton, input),
+ String.format("formatted number %s toDouble: %f", skeleton, input),
expectedDouble,
actualDouble);
assertBigDecimalEquals(
- String.format("compact decimal %s toBigDecimal: %f", skeleton, input),
+ String.format("formatted number %s toBigDecimal: %f", skeleton, input),
expectedBigDecimal,
actualBigDecimal);
assertEquals(
expectedPlainString,
actualPlainString);
assertEquals(
- String.format("compact decimal %s suppressed exponent: %f", skeleton, input),
- expectedSuppressedExponent,
- actualSuppressedExponent);
+ String.format("formatted number %s suppressed scientific exponent: %f", skeleton, input),
+ expectedSuppressedScientificExponent,
+ actualSuppressedScientificExponent);
+ assertEquals(
+ String.format("formatted number %s suppressed compact exponent: %f", skeleton, input),
+ expectedSuppressedCompactExponent,
+ actualSuppressedCompactExponent);
// test the actual computed values of the plural operands
double expectedNOperand = expectedDouble;
double expectedIOperand = expectedLong;
- double expectedEOperand = expectedSuppressedExponent;
+ double expectedEOperand = expectedSuppressedScientificExponent;
+ double expectedCOperand = expectedSuppressedCompactExponent;
double actualNOperand = dq.getPluralOperand(Operand.n);
double actualIOperand = dq.getPluralOperand(Operand.i);
double actualEOperand = dq.getPluralOperand(Operand.e);
+ double actualCOperand = dq.getPluralOperand(Operand.c);
assertEquals(
String.format("formatted number %s toString: %s", skeleton, input),
expectedString,
actualString);
assertDoubleEquals(
- String.format("compact decimal %s n operand: %f", skeleton, input),
+ String.format("formatted number %s n operand: %f", skeleton, input),
expectedNOperand,
actualNOperand);
assertDoubleEquals(
- String.format("compact decimal %s i operand: %f", skeleton, input),
+ String.format("formatted number %s i operand: %f", skeleton, input),
expectedIOperand,
actualIOperand);
assertDoubleEquals(
- String.format("compact decimal %s e operand: %f", skeleton, input),
+ String.format("formatted number %s e operand: %f", skeleton, input),
expectedEOperand,
actualEOperand);
+ assertDoubleEquals(
+ String.format("formatted number %s c operand: %f", skeleton, input),
+ expectedCOperand,
+ actualCOperand);
}
}
double expectedVOperand = 2;
double expectedWOperand = 1;
double expectedEOperand = 3;
+ double expectedCOperand = 3;
String expectedString = "1,23450 millier";
double actualNOperand = dq.getPluralOperand(Operand.n);
double actualIOperand = dq.getPluralOperand(Operand.i);
double actualVOperand = dq.getPluralOperand(Operand.v);
double actualWOperand = dq.getPluralOperand(Operand.w);
double actualEOperand = dq.getPluralOperand(Operand.e);
+ double actualCOperand = dq.getPluralOperand(Operand.c);
String actualString = fn.toString();
assertDoubleEquals(
String.format("compact decimal fraction e operand: %f", inputVal),
expectedEOperand,
actualEOperand);
+ assertDoubleEquals(
+ String.format("compact decimal fraction c operand: %f", inputVal),
+ expectedCOperand,
+ actualCOperand);
assertEquals(
String.format("compact decimal fraction toString: %f", inputVal),
expectedString,
Object[][] casesData = {
// input, compact long string output,
- // compact n operand, compact i operand, compact e operand
- {123456789, "123 millions", 123000000.0, 123000000.0, 6.0},
- {1234567, "1,2 million", 1200000.0, 1200000.0, 6.0},
- {123456, "123 mille", 123000.0, 123000.0, 3.0},
- {123, "123", 123.0, 123.0, 0.0},
+ // compact n operand, compact i operand, compact e operand,
+ // compact c operand
+ {123456789, "123 millions", 123000000.0, 123000000.0, 6.0, 6.0},
+ {1234567, "1,2 million", 1200000.0, 1200000.0, 6.0, 6.0},
+ {123456, "123 mille", 123000.0, 123000.0, 3.0, 3.0},
+ {123, "123", 123.0, 123.0, 0.0, 0.0},
};
for (Object[] caseDatum : casesData) {
double expectedNOperand = (double) caseDatum[2];
double expectedIOperand = (double) caseDatum[3];
double expectedEOperand = (double) caseDatum[4];
+ double expectedCOperand = (double) caseDatum[5];
FormattedNumber fnCompactScaled = compactScaled.format(input);
DecimalQuantity_DualStorageBCD dqCompactScaled =
(DecimalQuantity_DualStorageBCD) fnCompactScaled.getFixedDecimal();
- double compactScaledEOperand = dqCompactScaled.getPluralOperand(Operand.e);
+ double compactScaledCOperand = dqCompactScaled.getPluralOperand(Operand.c);
FormattedNumber fnCompact = compactLong.format(input);
DecimalQuantity_DualStorageBCD dqCompact =
double compactNOperand = dqCompact.getPluralOperand(Operand.n);
double compactIOperand = dqCompact.getPluralOperand(Operand.i);
double compactEOperand = dqCompact.getPluralOperand(Operand.e);
+ double compactCOperand = dqCompact.getPluralOperand(Operand.c);
assertEquals(
String.format("formatted number compactLong toString: %s", input),
expectedString,
String.format("compact decimal %d, e operand vs. expected", input),
expectedEOperand,
compactEOperand);
+ assertDoubleEquals(
+ String.format("compact decimal %d, c operand vs. expected", input),
+ expectedCOperand,
+ compactCOperand);
// By scaling by 10^3 in a locale that has words / compact notation
// based on powers of 10^3, we guarantee that the suppressed
// exponent will differ by 3.
assertDoubleEquals(
- String.format("decimal %d, e operand for compact vs. compact scaled", input),
- compactEOperand + 3,
- compactScaledEOperand);
+ String.format("decimal %d, c operand for compact vs. compact scaled", input),
+ compactCOperand + 3,
+ compactScaledCOperand);
}
}