From e3e7183663e297a35e5c3ae79246792af1161fec Mon Sep 17 00:00:00 2001 From: George Rhoten Date: Wed, 26 Aug 2015 10:42:17 +0000 Subject: [PATCH] ICU-11818 Implement PluralRules in fractional RBNF X-SVN-Rev: 37823 --- icu4c/source/i18n/nfrule.cpp | 12 ++++++++++-- icu4c/source/test/intltest/itrbnf.cpp | 25 +++++++++++++++++++++++-- icu4c/source/test/intltest/itrbnf.h | 1 + 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/icu4c/source/i18n/nfrule.cpp b/icu4c/source/i18n/nfrule.cpp index da55a212e53..f0e0953d802 100644 --- a/icu4c/source/i18n/nfrule.cpp +++ b/icu4c/source/i18n/nfrule.cpp @@ -792,8 +792,16 @@ NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, int32_ if (pluralRuleEnd < ruleText.length() - 1) { toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); } - toInsertInto.insert(pos, - rulePatternFormat->format((int32_t)(number/uprv_pow(radix, exponent)), status)); + double pluralVal = number; + if (0 <= pluralVal && pluralVal < 1) { + // We're in a fractional rule, and we have to match the NumeratorSubstitution behavior. + // 2.3 can become 0.2999999999999998 for the fraction due to rounding errors. + pluralVal = uprv_round(pluralVal * uprv_pow(radix, exponent)); + } + else { + pluralVal = pluralVal / uprv_pow(radix, exponent); + } + toInsertInto.insert(pos, rulePatternFormat->format((int32_t)(pluralVal), status)); if (pluralRuleStart > 0) { toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart)); } diff --git a/icu4c/source/test/intltest/itrbnf.cpp b/icu4c/source/test/intltest/itrbnf.cpp index c92d8536e6c..66ee2b8fca6 100644 --- a/icu4c/source/test/intltest/itrbnf.cpp +++ b/icu4c/source/test/intltest/itrbnf.cpp @@ -354,11 +354,17 @@ void IntlTestRBNF::TestMultiplePluralRules() { UnicodeString rules("%spellout-cardinal-feminine-genitive:" "0: zero;" "1: ono;" + "2: two;" "1000: << $(cardinal,one{thousand}few{thousanF}other{thousanO})$[ >>];" "%spellout-cardinal-feminine:" + "x.x: [<< $(cardinal,one{singleton}other{plurality})$ ]>%%fractions>;" "0: zero;" "1: one;" - "1000: << $(cardinal,one{thousand}few{thousanF}other{thousanO})$[ >>];"); + "2: two;" + "1000: << $(cardinal,one{thousand}few{thousanF}other{thousanO})$[ >>];" + "%%fractions:" + "10: <%spellout-cardinal-feminine< $(cardinal,one{oneth}other{tenth})$;" + "100: <%spellout-cardinal-feminine< $(cardinal,one{1hundredth}other{hundredth})$;"); UErrorCode status = U_ZERO_ERROR; UParseError pError; RuleBasedNumberFormat formatter(rules, Locale("ru"), pError, status); @@ -388,6 +394,21 @@ void IntlTestRBNF::TestMultiplePluralRules() { errln("RuleBasedNumberFormat(spellout-cardinal-feminine) did not return the correct value. Got: %d", result.getLong()); errln(resultStr); } + static const char* const testData[][2] = { + { "0", "zero" }, + { "1", "one" }, + { "2", "two" }, + { "0.1", "one oneth" }, + { "0.2", "two tenth" }, + { "1.1", "one singleton one oneth" }, + { "1.2", "one singleton two tenth" }, + { "2.1", "two plurality one oneth" }, + { "2.2", "two plurality two tenth" }, + { "0.01", "one 1hundredth" }, + { "0.02", "two hundredth" }, + { NULL, NULL } + }; + doTest(&formatter, testData, TRUE); } void IntlTestRBNF::TestFractionalRuleSet() @@ -475,7 +496,7 @@ void IntlTestRBNF::TestFractionalRuleSet() { "1.2856", "1 2/7" }, { NULL, NULL } }; - doTest(&formatter, testData, FALSE); // exact values aren't parsable from fractions + doTest(&formatter, testData, FALSE); // exact values aren't parsable from fractions } } diff --git a/icu4c/source/test/intltest/itrbnf.h b/icu4c/source/test/intltest/itrbnf.h index f84ff9eb5e7..8d52555aba4 100644 --- a/icu4c/source/test/intltest/itrbnf.h +++ b/icu4c/source/test/intltest/itrbnf.h @@ -142,6 +142,7 @@ class IntlTestRBNF : public IntlTest { void TestInfinityNaN(); void TestVariableDecimalPoint(); + void TestRounding(); protected: virtual void doTest(RuleBasedNumberFormat* formatter, const char* const testData[][2], UBool testParsing); -- 2.40.0