Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICU-21519 Make compact notation 'c' behave like 'e' in FixedDecimal #1624

Merged
merged 1 commit into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions icu4c/source/i18n/number_decimalquantity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@ double DecimalQuantity::getPluralOperand(PluralOperand operand) const {
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());
}
Expand Down
49 changes: 43 additions & 6 deletions icu4c/source/i18n/plurrule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ static const UChar PK_VAR_I[]={LOW_I,0};
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};
Expand Down Expand Up @@ -421,7 +422,6 @@ getSamplesFromString(const UnicodeString &samples, double *destDbl,
destFd[sampleCount++] = fixed;
}
} else {

FixedDecimal fixedLo(sampleRange.tempSubStringBetween(0, tildeIndex), status);
FixedDecimal fixedHi(sampleRange.tempSubStringBetween(tildeIndex+1), status);
double rangeLo = fixedLo.source;
Expand Down Expand Up @@ -514,6 +514,7 @@ PluralRules::getSamples(const UnicodeString &keyword, FixedDecimal *dest,
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);
Expand Down Expand Up @@ -706,6 +707,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
case tVariableF:
case tVariableT:
case tVariableE:
case tVariableC:
case tVariableV:
U_ASSERT(curAndConstraint != nullptr);
curAndConstraint->digitsType = type;
Expand Down Expand Up @@ -1092,6 +1094,8 @@ static UnicodeString tokenString(tokenType tok) {
s.append(LOW_T); break;
case tVariableE:
s.append(LOW_E); break;
case tVariableC:
s.append(LOW_C); break;
default:
s.append(TILDE);
}
Expand Down Expand Up @@ -1269,6 +1273,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
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) {
Expand All @@ -1286,6 +1291,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
type == tVariableF ||
type == tVariableT ||
type == tVariableE ||
type == tVariableC ||
type == tVariableV ||
type == tAt)) {
status = U_UNEXPECTED_TOKEN;
Expand Down Expand Up @@ -1318,6 +1324,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
type != tVariableF &&
type != tVariableT &&
type != tVariableE &&
type != tVariableC &&
type != tVariableV) {
status = U_UNEXPECTED_TOKEN;
}
Expand Down Expand Up @@ -1497,6 +1504,8 @@ PluralRuleParser::getKeyType(const UnicodeString &token, tokenType keyType)
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)) {
Expand Down Expand Up @@ -1596,11 +1605,17 @@ PluralOperand tokenTypeToPluralOperand(tokenType tt) {
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.
Expand Down Expand Up @@ -1642,16 +1657,30 @@ FixedDecimal::FixedDecimal() {
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);
}
Expand Down Expand Up @@ -1706,13 +1735,20 @@ void FixedDecimal::init(double n, int32_t v, int64_t f) {
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;
Expand Down Expand Up @@ -1843,6 +1879,7 @@ double FixedDecimal::getPluralOperand(PluralOperand operand) const {
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.
}
Expand Down Expand Up @@ -1876,12 +1913,12 @@ bool FixedDecimal::operator==(const FixedDecimal &other) const {
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);
}
Expand Down
19 changes: 16 additions & 3 deletions icu4c/source/i18n/plurrule_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ enum tokenType {
tVariableV,
tVariableT,
tVariableE,
tVariableC,
tDecimal,
tInteger,
tEOF
Expand Down Expand Up @@ -222,11 +223,20 @@ enum PluralOperand {
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.
*
Expand Down Expand Up @@ -280,8 +290,10 @@ class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject {
* @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);
Expand All @@ -302,6 +314,7 @@ class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject {

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);
Expand Down
2 changes: 1 addition & 1 deletion icu4c/source/test/intltest/numbertest.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ class DecimalQuantityTest : public IntlTest {
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);
Expand Down
Loading