ICU-10273 Plural Rules, add DecimalFormat::getFixedDecimal(). Work in progress.

X-SVN-Rev: 34176
This commit is contained in:
Andy Heninger 2013-09-04 01:07:35 +00:00
parent df276b7a30
commit 003c35c1d9
7 changed files with 137 additions and 5 deletions

View File

@ -1020,6 +1020,25 @@ DecimalFormat::clone() const
return new DecimalFormat(*this);
}
FixedDecimal
DecimalFormat::getFixedDecimal(double number, UErrorCode &status) {
DigitList digits;
digits.set(number);
UBool isNegative;
_round(digits, digits, isNegative, status);
double roundedNum = digits.getDouble();
FixedDecimal result(roundedNum);
int32_t numTrailingFractionZeros = this->getMinimumFractionDigits() - result.visibleDecimalDigitCount;
if (numTrailingFractionZeros > 0) {
double scaleFactor = pow(10.0, numTrailingFractionZeros);
result.decimalDigits *= scaleFactor;
result.visibleDecimalDigitCount += numTrailingFractionZeros;
}
return result;
}
//------------------------------------------------------------------------------
UnicodeString&
@ -1389,6 +1408,10 @@ DecimalFormat::_round(const DigitList &number, DigitList &adjustedNum, UBool& is
if (U_FAILURE(status)) {
return adjustedNum;
}
// note: number and adjustedNum may refer to the same DigitList, in cases where a copy
// is not needed by the caller.
adjustedNum = number;
isNegative = false;
if (number.isNaN()) {

View File

@ -458,6 +458,10 @@ ArgExtractor::number(void) const {
return num;
}
// TODO: Thread safety problem? the function of ArgExtractor appears to be to temporarily
// setCurrency() on the number formatter, then restore it after the format() is complete.
// Another thread could be using the formatter.
ArgExtractor::ArgExtractor(const NumberFormat& nf, const Formattable& obj, UErrorCode& status)
: ncnf((NumberFormat*) &nf), num(&obj), setCurr(FALSE) {

View File

@ -1357,6 +1357,18 @@ FixedDecimal::FixedDecimal(const UnicodeString &num, UErrorCode &status) {
}
FixedDecimal::FixedDecimal(const FixedDecimal &other) {
source = other.source;
visibleDecimalDigitCount = other.visibleDecimalDigitCount;
decimalDigits = other.decimalDigits;
decimalDigitsWithoutTrailingZeros = other.decimalDigitsWithoutTrailingZeros;
intValue = other.intValue;
hasIntegerValue = other.hasIntegerValue;
isNegative = other.isNegative;
isNanOrInfinity = other.isNanOrInfinity;
}
void FixedDecimal::init(double n, int32_t v, int64_t f) {
isNegative = n < 0;
source = fabs(n);
@ -1373,6 +1385,9 @@ void FixedDecimal::init(double n, int32_t v, int64_t f) {
}
decimalDigitsWithoutTrailingZeros = fdwtz;
}
if (uprv_isNaN(n)) {
isNanOrInfinity = TRUE;
}
}
int32_t FixedDecimal::decimals(double n) {

View File

@ -29,6 +29,9 @@ class PluralRulesTest;
U_NAMESPACE_BEGIN
class AndConstraint;
class RuleChain;
static const UChar DOT = ((UChar)0x002E);
static const UChar SINGLE_QUOTE = ((UChar)0x0027);
static const UChar SLASH = ((UChar)0x002F);
@ -179,6 +182,7 @@ class U_I18N_API FixedDecimal: public UMemory {
FixedDecimal(double n, int32_t);
explicit FixedDecimal(double n);
FixedDecimal(const UnicodeString &s, UErrorCode &ec);
FixedDecimal(const FixedDecimal &other);
double get(tokenType operand) const;
int32_t getVisibleFractionDigitCount() const;
@ -194,6 +198,7 @@ class U_I18N_API FixedDecimal: public UMemory {
int64_t intValue;
UBool hasIntegerValue;
UBool isNegative;
UBool isNanOrInfinity;
};
class AndConstraint : public UMemory {

View File

@ -60,6 +60,7 @@ class Hashtable;
class UnicodeSet;
class FieldPositionHandler;
class DecimalFormatStaticSets;
class FixedDecimal;
// explicit template instantiation. see digitlst.h
#if defined (_MSC_VER)
@ -1852,6 +1853,14 @@ public:
*/
static const char fgNumberPatterns[];
/**
* Get a FixedDecimal corresponding to a double as it would be
* formatted by this DecimalFormat.
* Internal, not intended for public use.
* @internal
*/
FixedDecimal getFixedDecimal(double number, UErrorCode &status);
public:
/**

View File

@ -10,10 +10,13 @@
#include "dcfmapts.h"
#include "unicode/decimfmt.h"
#include "unicode/dcfmtsym.h"
#include "unicode/parseerr.h"
#include "unicode/currpinf.h"
#include "unicode/dcfmtsym.h"
#include "unicode/decimfmt.h"
#include "unicode/localpointer.h"
#include "unicode/parseerr.h"
#include "plurrule_impl.h"
#define LENGTHOF(array) ((int32_t)(sizeof(array)/sizeof((array)[0])))
@ -62,7 +65,13 @@ void IntlTestDecimalFormatAPI::runIndexedTest( int32_t index, UBool exec, const
TestScale();
}
break;
default: name = ""; break;
case 5: name = "TestFixedDecimal";
if(exec) {
logln((UnicodeString)"TestFixedDecimal ---");
TestFixedDecimal();
}
break;
default: name = ""; break;
}
}
@ -553,7 +562,8 @@ void IntlTestDecimalFormatAPI::TestScale()
}
pat.setAttribute(UNUM_SCALE,testData[i].inputScale,status);
pat.format(testData[i].inputValue, resultStr);
message = UnicodeString("Unexpected output for ") + testData[i].inputValue + UnicodeString(" and scale ") + testData[i].inputScale + UnicodeString(". Got: ");
message = UnicodeString("Unexpected output for ") + testData[i].inputValue + UnicodeString(" and scale ") +
testData[i].inputScale + UnicodeString(". Got: ");
exp = testData[i].expectedOutput;
verifyString(message, resultStr, exp);
message.remove();
@ -561,4 +571,69 @@ void IntlTestDecimalFormatAPI::TestScale()
exp.remove();
}
}
#define ASSERT_SUCCESS(status) {if (U_FAILURE(status)) { \
errln("file %s, line %d: Error status is %s", __FILE__, __LINE__, u_errorName(status)); \
status = U_ZERO_ERROR; }}
#define ASSERT_EQUAL(expect, actual) {if ((expect) != (actual)) { \
errln("file %s, line %d: Expected %g, got %g", __FILE__, __LINE__, (double)(expect), (double)(actual)); }}
void IntlTestDecimalFormatAPI::TestFixedDecimal() {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<DecimalFormat> df(new DecimalFormat("###", status));
ASSERT_SUCCESS(status);
FixedDecimal fd = df->getFixedDecimal(44, status);
ASSERT_SUCCESS(status);
ASSERT_EQUAL(44, fd.source);
ASSERT_EQUAL(0, fd.visibleDecimalDigitCount);
df.adoptInstead(new DecimalFormat("###.00##", status));
ASSERT_SUCCESS(status);
fd = df->getFixedDecimal(123.456, status);
ASSERT_SUCCESS(status);
ASSERT_EQUAL(3, fd.visibleDecimalDigitCount);
ASSERT_EQUAL(456, fd.decimalDigits);
ASSERT_EQUAL(456, fd.decimalDigitsWithoutTrailingZeros);
ASSERT_EQUAL(123, fd.intValue);
ASSERT_EQUAL(FALSE, fd.hasIntegerValue);
ASSERT_EQUAL(FALSE, fd.isNegative);
df.adoptInstead(new DecimalFormat("###", status));
ASSERT_SUCCESS(status);
fd = df->getFixedDecimal(123.456, status);
ASSERT_SUCCESS(status);
ASSERT_EQUAL(0, fd.visibleDecimalDigitCount);
ASSERT_EQUAL(0, fd.decimalDigits);
ASSERT_EQUAL(0, fd.decimalDigitsWithoutTrailingZeros);
ASSERT_EQUAL(123, fd.intValue);
ASSERT_EQUAL(TRUE, fd.hasIntegerValue);
ASSERT_EQUAL(FALSE, fd.isNegative);
df.adoptInstead(new DecimalFormat("###.0", status));
ASSERT_SUCCESS(status);
fd = df->getFixedDecimal(123.01, status);
ASSERT_SUCCESS(status);
ASSERT_EQUAL(1, fd.visibleDecimalDigitCount);
ASSERT_EQUAL(0, fd.decimalDigits);
ASSERT_EQUAL(0, fd.decimalDigitsWithoutTrailingZeros);
ASSERT_EQUAL(123, fd.intValue);
ASSERT_EQUAL(TRUE, fd.hasIntegerValue);
ASSERT_EQUAL(FALSE, fd.isNegative);
df.adoptInstead(new DecimalFormat("###.0", status));
ASSERT_SUCCESS(status);
fd = df->getFixedDecimal(123.06, status);
ASSERT_SUCCESS(status);
ASSERT_EQUAL(1, fd.visibleDecimalDigitCount);
ASSERT_EQUAL(1, fd.decimalDigits);
ASSERT_EQUAL(1, fd.decimalDigitsWithoutTrailingZeros);
ASSERT_EQUAL(123, fd.intValue);
ASSERT_EQUAL(FALSE, fd.hasIntegerValue);
ASSERT_EQUAL(FALSE, fd.isNegative);
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View File

@ -28,6 +28,7 @@ public:
void testRoundingInc(/*char *par*/);
void TestCurrencyPluralInfo();
void TestScale();
void TestFixedDecimal();
private:
/*Helper functions */
void verify(const UnicodeString& message, const UnicodeString& got, double expected);