}
+FixedDecimal
+DecimalFormat::getFixedDecimal(const Formattable &number, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return FixedDecimal();
+ }
+ if (!number.isNumeric()) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return FixedDecimal();
+ }
+
+ DigitList *digits = number.getDigitList();
+ if (digits == NULL || digits->getCount() <= 15) {
+ return getFixedDecimal(number.getDouble(), status);
+ }
+
+ // We have an incoming DigitList in the formattable, and it holds more digits than
+ // a double can safely represent.
+ // Compute the fields of the fixed decimal directly from the digit list.
+
+ FixedDecimal result;
+ result.source = digits->getDouble();
+
+ // Round the number according to the requirements of this Format.
+ DigitList roundedNum;
+ _round(*digits, roundedNum, result.isNegative, status);
+
+ // The int64_t fields in FixedDecimal can easily overflow.
+ // In deciding what to discard in this event, consider that fixedDecimal
+ // is being used only with PluralRules, and those rules mostly look at least significant
+ // few digits of the integer part, and whether the fraction part is zero or not.
+ //
+ // So, in case of overflow when filling in the fields of the FixedDecimal object,
+ // for the integer part, discard the most significant digits.
+ // for the fraction part, discard the least significant digits,
+ // don't truncate the fraction value to zero.
+ // For simplicity, the int64_t fields are limited to 18 decimal digits, even
+ // though they could hold most (but not all) 19 digit values.
+
+ // Integer Digits.
+ int32_t di = roundedNum.getDecimalAt()-18; // Take at most 18 digits.
+ if (di < 0) {
+ di = 0;
+ }
+ result.intValue = 0;
+ for (; di<roundedNum.getDecimalAt(); di++) {
+ result.intValue = result.intValue * 10 + (roundedNum.getDigit(di) & 0x0f);
+ }
+
+ // Fraction digits.
+ result.visibleDecimalDigitCount = result.decimalDigits = result.decimalDigitsWithoutTrailingZeros = 0;
+ for (di = roundedNum.getDecimalAt(); di < roundedNum.getCount(); di++) {
+ result.visibleDecimalDigitCount++;
+ if (result.decimalDigits < 100000000000000000LL) {
+ // 9223372036854775807 Largest 64 bit signed integer
+ int32_t digitVal = roundedNum.getDigit(di) & 0x0f; // getDigit() returns a char, '0'-'9'.
+ result.decimalDigits = result.decimalDigits * 10 + digitVal;
+ if (digitVal > 0) {
+ result.decimalDigitsWithoutTrailingZeros = result.decimalDigits;
+ }
+ }
+ }
+
+ result.hasIntegerValue = (result.decimalDigits == 0);
+ return result;
+}
+
+
//------------------------------------------------------------------------------
UnicodeString&
#include "unicode/currpinf.h"
#include "unicode/dcfmtsym.h"
#include "unicode/decimfmt.h"
+#include "unicode/fmtable.h"
#include "unicode/localpointer.h"
#include "unicode/parseerr.h"
+#include "unicode/stringpiece.h"
#include "putilimp.h"
#include "plurrule_impl.h"
fd = df->getFixedDecimal(uprv_getNaN(), status);
ASSERT_EQUAL(TRUE, fd.isNanOrInfinity);
ASSERT_SUCCESS(status);
+
+ // Test Big Decimal input.
+ // 22 digits before and after decimal, will exceed the precision of a double
+ // and force DecimalFormat::getFixedDecimal() to work with a digit list.
+ df.adoptInstead(new DecimalFormat("#####################0.00####################", status));
+ ASSERT_SUCCESS(status);
+ Formattable fable("12.34", status);
+ ASSERT_SUCCESS(status);
+ fd = df->getFixedDecimal(fable, status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUAL(2, fd.visibleDecimalDigitCount);
+ ASSERT_EQUAL(34, fd.decimalDigits);
+ ASSERT_EQUAL(34, fd.decimalDigitsWithoutTrailingZeros);
+ ASSERT_EQUAL(12, fd.intValue);
+ ASSERT_EQUAL(FALSE, fd.hasIntegerValue);
+ ASSERT_EQUAL(FALSE, fd.isNegative);
+
+ fable.setDecimalNumber("12.345678901234567890123456789", status);
+ ASSERT_SUCCESS(status);
+ fd = df->getFixedDecimal(fable, status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUAL(22, fd.visibleDecimalDigitCount);
+ ASSERT_EQUAL(345678901234567890LL, fd.decimalDigits);
+ ASSERT_EQUAL(34567890123456789LL, fd.decimalDigitsWithoutTrailingZeros);
+ ASSERT_EQUAL(12, fd.intValue);
+ ASSERT_EQUAL(FALSE, fd.hasIntegerValue);
+ ASSERT_EQUAL(FALSE, fd.isNegative);
+
+ // On field overflow, Integer part is truncated on the left, fraction part on the right.
+ fable.setDecimalNumber("123456789012345678901234567890.123456789012345678901234567890", status);
+ ASSERT_SUCCESS(status);
+ fd = df->getFixedDecimal(fable, status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUAL(22, fd.visibleDecimalDigitCount);
+ ASSERT_EQUAL(123456789012345678LL, fd.decimalDigits);
+ ASSERT_EQUAL(123456789012345678LL, fd.decimalDigitsWithoutTrailingZeros);
+ ASSERT_EQUAL(345678901234567890LL, fd.intValue);
+ ASSERT_EQUAL(FALSE, fd.hasIntegerValue);
+ ASSERT_EQUAL(FALSE, fd.isNegative);
+
+ // Digits way to the right of the decimal but within the format's precision aren't truncated
+ fable.setDecimalNumber("1.0000000000000000000012", status);
+ ASSERT_SUCCESS(status);
+ fd = df->getFixedDecimal(fable, status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUAL(22, fd.visibleDecimalDigitCount);
+ ASSERT_EQUAL(12, fd.decimalDigits);
+ ASSERT_EQUAL(12, fd.decimalDigitsWithoutTrailingZeros);
+ ASSERT_EQUAL(1, fd.intValue);
+ ASSERT_EQUAL(FALSE, fd.hasIntegerValue);
+ ASSERT_EQUAL(FALSE, fd.isNegative);
+
+ // Digits beyond the precision of the format are rounded away
+ fable.setDecimalNumber("1.000000000000000000000012", status);
+ ASSERT_SUCCESS(status);
+ fd = df->getFixedDecimal(fable, status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUAL(0, fd.visibleDecimalDigitCount);
+ ASSERT_EQUAL(0, fd.decimalDigits);
+ ASSERT_EQUAL(0, fd.decimalDigitsWithoutTrailingZeros);
+ ASSERT_EQUAL(1, fd.intValue);
+ ASSERT_EQUAL(TRUE, fd.hasIntegerValue);
+ ASSERT_EQUAL(FALSE, fd.isNegative);
+
+ // Negative numbers come through
+ fable.setDecimalNumber("-1.0000000000000000000012", status);
+ ASSERT_SUCCESS(status);
+ fd = df->getFixedDecimal(fable, status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUAL(22, fd.visibleDecimalDigitCount);
+ ASSERT_EQUAL(12, fd.decimalDigits);
+ ASSERT_EQUAL(12, fd.decimalDigitsWithoutTrailingZeros);
+ ASSERT_EQUAL(1, fd.intValue);
+ ASSERT_EQUAL(FALSE, fd.hasIntegerValue);
+ ASSERT_EQUAL(TRUE, fd.isNegative);
+
}
#endif /* #if !UCONFIG_NO_FORMATTING */