mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
ICU-10273 Plural Rules, add DecimalFormat::getFixedDecimal(). Work in progress.
X-SVN-Rev: 34204
This commit is contained in:
parent
bcfcd53be9
commit
7b3b75a525
5 changed files with 103 additions and 14 deletions
icu4c/source
|
@ -1022,19 +1022,42 @@ DecimalFormat::clone() const
|
|||
|
||||
|
||||
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;
|
||||
DecimalFormat::getFixedDecimal(double number, UErrorCode &status) const {
|
||||
FixedDecimal result;
|
||||
int32_t minFractionDigits = getMinimumFractionDigits();
|
||||
|
||||
if (fMultiplier == NULL && fScale == 0 && fRoundingIncrement == 0 && areSignificantDigitsUsed() == FALSE &&
|
||||
result.quickInit(number) && result.visibleDecimalDigitCount <= getMaximumFractionDigits()) {
|
||||
// Fast Path. Construction of an exact FixedDecimal directly from the double, without passing
|
||||
// through a DigitList, was successful, and the formatter is doing nothing tricky with rounding.
|
||||
// printf("getFixedDecimal(%g): taking fast path.\n", number);
|
||||
} else {
|
||||
// Slow path. Create a DigitList, and have this formatter round it according to the
|
||||
// requirements of the format, and fill the fixedDecimal from that.
|
||||
DigitList digits;
|
||||
digits.set(number);
|
||||
UBool isNegative;
|
||||
_round(digits, digits, isNegative, status);
|
||||
double roundedNum = digits.getDouble();
|
||||
result.init(roundedNum);
|
||||
|
||||
if (areSignificantDigitsUsed()) {
|
||||
minFractionDigits = getMinimumSignificantDigits() - digits.getDecimalAt();
|
||||
if (minFractionDigits < 0) {
|
||||
minFractionDigits = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust result for trailing zeros to the right of the decimal. Needed for both fast & slow paths.
|
||||
|
||||
int32_t numTrailingFractionZeros = minFractionDigits - result.visibleDecimalDigitCount;
|
||||
if (numTrailingFractionZeros > 0) {
|
||||
double scaleFactor = pow(10.0, numTrailingFractionZeros);
|
||||
result.decimalDigits *= scaleFactor;
|
||||
result.visibleDecimalDigitCount += numTrailingFractionZeros;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1330,10 +1330,14 @@ FixedDecimal::FixedDecimal(double n, int32_t v) {
|
|||
}
|
||||
|
||||
FixedDecimal::FixedDecimal(double n) {
|
||||
int64_t numFractionDigits = decimals(n);
|
||||
init(n, numFractionDigits, getFractionalDigits(n, numFractionDigits));
|
||||
init(n);
|
||||
}
|
||||
|
||||
FixedDecimal::FixedDecimal() {
|
||||
init(0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
// Create a FixedDecimal from a UnicodeString containing a number.
|
||||
// Inefficient, but only used for samples, so simplicity trumps efficiency.
|
||||
|
||||
|
@ -1369,6 +1373,12 @@ FixedDecimal::FixedDecimal(const FixedDecimal &other) {
|
|||
}
|
||||
|
||||
|
||||
void FixedDecimal::init(double n) {
|
||||
int64_t numFractionDigits = decimals(n);
|
||||
init(n, numFractionDigits, getFractionalDigits(n, numFractionDigits));
|
||||
}
|
||||
|
||||
|
||||
void FixedDecimal::init(double n, int32_t v, int64_t f) {
|
||||
isNegative = n < 0;
|
||||
source = fabs(n);
|
||||
|
@ -1390,17 +1400,43 @@ void FixedDecimal::init(double n, int32_t v, int64_t f) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Fast path only exact initialization. Return true if successful.
|
||||
// Note: Do not multiply by 10 each time through loop, rounding cruft can build
|
||||
// up that makes the check for an integer result fail.
|
||||
// A single multiply of the original number works more reliably.
|
||||
static int p10[] = {1, 10, 100, 1000, 10000};
|
||||
UBool FixedDecimal::quickInit(double n) {
|
||||
UBool success = FALSE;
|
||||
n = fabs(n);
|
||||
int32_t numFractionDigits;
|
||||
for (numFractionDigits = 0; numFractionDigits <= 3; numFractionDigits++) {
|
||||
double scaledN = n * p10[numFractionDigits];
|
||||
if (scaledN == floor(scaledN)) {
|
||||
success = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
init(n, numFractionDigits, getFractionalDigits(n, numFractionDigits));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t FixedDecimal::decimals(double n) {
|
||||
// Count the number of decimal digits in the fraction part of the number, excluding trailing zeros.
|
||||
// fastpath the common cases, integers or fractions with 3 or fewer digits
|
||||
n = fabs(n);
|
||||
double scaledN = n;
|
||||
for (int ndigits=0; ndigits<=3; ndigits++) {
|
||||
// fastpath the common cases, integers or fractions with 3 or fewer digits
|
||||
double scaledN = n * p10[ndigits];
|
||||
if (scaledN == floor(scaledN)) {
|
||||
return ndigits;
|
||||
}
|
||||
scaledN *= 10;
|
||||
}
|
||||
|
||||
// Slow path, convert with sprintf, parse converted output.
|
||||
char buf[30] = {0};
|
||||
sprintf(buf, "%1.15e", n);
|
||||
// formatted number looks like this: 1.234567890123457e-01
|
||||
|
|
|
@ -181,6 +181,7 @@ class U_I18N_API FixedDecimal: public UMemory {
|
|||
FixedDecimal(double n, int32_t v, int64_t f);
|
||||
FixedDecimal(double n, int32_t);
|
||||
explicit FixedDecimal(double n);
|
||||
FixedDecimal();
|
||||
FixedDecimal(const UnicodeString &s, UErrorCode &ec);
|
||||
FixedDecimal(const FixedDecimal &other);
|
||||
|
||||
|
@ -188,6 +189,9 @@ class U_I18N_API FixedDecimal: public UMemory {
|
|||
int32_t getVisibleFractionDigitCount() const;
|
||||
|
||||
void init(double n, int32_t v, int64_t f);
|
||||
void init(double n);
|
||||
UBool quickInit(double n); // Try a fast-path only initialization,
|
||||
// return TRUE if successful.
|
||||
static int64_t getFractionalDigits(double n, int32_t v);
|
||||
static int32_t decimals(double n);
|
||||
|
||||
|
|
|
@ -1859,7 +1859,7 @@ public:
|
|||
* Internal, not intended for public use.
|
||||
* @internal
|
||||
*/
|
||||
FixedDecimal getFixedDecimal(double number, UErrorCode &status);
|
||||
FixedDecimal getFixedDecimal(double number, UErrorCode &status) const;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -634,6 +634,32 @@ void IntlTestDecimalFormatAPI::TestFixedDecimal() {
|
|||
ASSERT_EQUAL(123, fd.intValue);
|
||||
ASSERT_EQUAL(FALSE, fd.hasIntegerValue);
|
||||
ASSERT_EQUAL(FALSE, fd.isNegative);
|
||||
|
||||
df.adoptInstead(new DecimalFormat("@@@@@", status)); // Significant Digits
|
||||
ASSERT_SUCCESS(status);
|
||||
fd = df->getFixedDecimal(123, status);
|
||||
ASSERT_SUCCESS(status);
|
||||
ASSERT_EQUAL(2, 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("@@@@@", status)); // Significant Digits
|
||||
ASSERT_SUCCESS(status);
|
||||
fd = df->getFixedDecimal(1.23, status);
|
||||
ASSERT_SUCCESS(status);
|
||||
ASSERT_EQUAL(4, fd.visibleDecimalDigitCount);
|
||||
ASSERT_EQUAL(2300, fd.decimalDigits);
|
||||
ASSERT_EQUAL(23, fd.decimalDigitsWithoutTrailingZeros);
|
||||
ASSERT_EQUAL(1, fd.intValue);
|
||||
ASSERT_EQUAL(FALSE, fd.hasIntegerValue);
|
||||
ASSERT_EQUAL(FALSE, fd.isNegative);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
Loading…
Add table
Reference in a new issue