|  | /* | 
|  | ********************************************************************** | 
|  | *   Copyright (C) 1997-2012, International Business Machines | 
|  | *   Corporation and others.  All Rights Reserved. | 
|  | ********************************************************************** | 
|  | * | 
|  | * File DIGITLST.CPP | 
|  | * | 
|  | * Modification History: | 
|  | * | 
|  | *   Date        Name        Description | 
|  | *   03/21/97    clhuang     Converted from java. | 
|  | *   03/21/97    clhuang     Implemented with new APIs. | 
|  | *   03/27/97    helena      Updated to pass the simple test after code review. | 
|  | *   03/31/97    aliu        Moved isLONG_MIN to here, and fixed it. | 
|  | *   04/15/97    aliu        Changed MAX_COUNT to DBL_DIG.  Changed Digit to char. | 
|  | *                           Reworked representation by replacing fDecimalAt | 
|  | *                           with fExponent. | 
|  | *   04/16/97    aliu        Rewrote set() and getDouble() to use sprintf/atof | 
|  | *                           to do digit conversion. | 
|  | *   09/09/97    aliu        Modified for exponential notation support. | 
|  | *   08/02/98    stephen     Added nearest/even rounding | 
|  | *                            Fixed bug in fitsIntoLong | 
|  | ****************************************************************************** | 
|  | */ | 
|  |  | 
|  | #include "digitlst.h" | 
|  |  | 
|  | #if !UCONFIG_NO_FORMATTING | 
|  | #include "unicode/putil.h" | 
|  | #include "charstr.h" | 
|  | #include "cmemory.h" | 
|  | #include "cstring.h" | 
|  | #include "mutex.h" | 
|  | #include "putilimp.h" | 
|  | #include "uassert.h" | 
|  | #include <stdlib.h> | 
|  | #include <limits.h> | 
|  | #include <string.h> | 
|  | #include <stdio.h> | 
|  | #include <limits> | 
|  |  | 
|  | // *************************************************************************** | 
|  | // class DigitList | 
|  | //    A wrapper onto decNumber. | 
|  | //    Used to be standalone. | 
|  | // *************************************************************************** | 
|  |  | 
|  | /** | 
|  | * This is the zero digit.  The base for the digits returned by getDigit() | 
|  | * Note that it is the platform invariant digit, and is not Unicode. | 
|  | */ | 
|  | #define kZero '0' | 
|  |  | 
|  |  | 
|  | /* Only for 32 bit numbers. Ignore the negative sign. */ | 
|  | //static const char LONG_MIN_REP[] = "2147483648"; | 
|  | //static const char I64_MIN_REP[] = "9223372036854775808"; | 
|  |  | 
|  |  | 
|  | static const uint8_t DIGIT_HAVE_NONE=0; | 
|  | static const uint8_t DIGIT_HAVE_DOUBLE=1; | 
|  | static const uint8_t DIGIT_HAVE_INT64=2; | 
|  |  | 
|  | U_NAMESPACE_BEGIN | 
|  |  | 
|  | // ------------------------------------- | 
|  | // default constructor | 
|  |  | 
|  | DigitList::DigitList() | 
|  | { | 
|  | uprv_decContextDefault(&fContext, DEC_INIT_BASE); | 
|  | fContext.traps  = 0; | 
|  | uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN); | 
|  | fContext.digits = fStorage.getCapacity(); | 
|  |  | 
|  | fDecNumber = fStorage.getAlias(); | 
|  | uprv_decNumberZero(fDecNumber); | 
|  |  | 
|  | internalSetDouble(0.0); | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  |  | 
|  | DigitList::~DigitList() | 
|  | { | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  | // copy constructor | 
|  |  | 
|  | DigitList::DigitList(const DigitList &other) | 
|  | { | 
|  | fDecNumber = fStorage.getAlias(); | 
|  | *this = other; | 
|  | } | 
|  |  | 
|  |  | 
|  | // ------------------------------------- | 
|  | // assignment operator | 
|  |  | 
|  | DigitList& | 
|  | DigitList::operator=(const DigitList& other) | 
|  | { | 
|  | if (this != &other) | 
|  | { | 
|  | uprv_memcpy(&fContext, &other.fContext, sizeof(decContext)); | 
|  |  | 
|  | if (other.fStorage.getCapacity() > fStorage.getCapacity()) { | 
|  | fDecNumber = fStorage.resize(other.fStorage.getCapacity()); | 
|  | } | 
|  | // Always reset the fContext.digits, even if fDecNumber was not reallocated, | 
|  | // because above we copied fContext from other.fContext. | 
|  | fContext.digits = fStorage.getCapacity(); | 
|  | uprv_decNumberCopy(fDecNumber, other.fDecNumber); | 
|  |  | 
|  | { | 
|  | // fDouble is lazily created and cached. | 
|  | // Avoid potential races with that happening with other.fDouble | 
|  | // while we are doing the assignment. | 
|  | Mutex mutex; | 
|  |  | 
|  | if(other.fHave==kDouble) { | 
|  | fUnion.fDouble = other.fUnion.fDouble; | 
|  | } else if(other.fHave==kInt64) { | 
|  | fUnion.fInt64 = other.fUnion.fInt64; | 
|  | } | 
|  | fHave = other.fHave; | 
|  | } | 
|  | } | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  | //    operator ==  (does not exactly match the old DigitList function) | 
|  |  | 
|  | UBool | 
|  | DigitList::operator==(const DigitList& that) const | 
|  | { | 
|  | if (this == &that) { | 
|  | return TRUE; | 
|  | } | 
|  | decNumber n;  // Has space for only a none digit value. | 
|  | decContext c; | 
|  | uprv_decContextDefault(&c, DEC_INIT_BASE); | 
|  | c.digits = 1; | 
|  | c.traps = 0; | 
|  |  | 
|  | uprv_decNumberCompare(&n, this->fDecNumber, that.fDecNumber, &c); | 
|  | UBool result = decNumberIsZero(&n); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  | //      comparison function.   Returns | 
|  | //         Not Comparable :  -2 | 
|  | //                      < :  -1 | 
|  | //                     == :   0 | 
|  | //                      > :  +1 | 
|  | int32_t DigitList::compare(const DigitList &other) { | 
|  | decNumber   result; | 
|  | int32_t     savedDigits = fContext.digits; | 
|  | fContext.digits = 1; | 
|  | uprv_decNumberCompare(&result, this->fDecNumber, other.fDecNumber, &fContext); | 
|  | fContext.digits = savedDigits; | 
|  | if (decNumberIsZero(&result)) { | 
|  | return 0; | 
|  | } else if (decNumberIsSpecial(&result)) { | 
|  | return -2; | 
|  | } else if (result.bits & DECNEG) { | 
|  | return -1; | 
|  | } else { | 
|  | return 1; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | // ------------------------------------- | 
|  | //  Reduce - remove trailing zero digits. | 
|  | void | 
|  | DigitList::reduce() { | 
|  | uprv_decNumberReduce(fDecNumber, fDecNumber, &fContext); | 
|  | } | 
|  |  | 
|  |  | 
|  | // ------------------------------------- | 
|  | //  trim - remove trailing fraction zero digits. | 
|  | void | 
|  | DigitList::trim() { | 
|  | uprv_decNumberTrim(fDecNumber); | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  | // Resets the digit list; sets all the digits to zero. | 
|  |  | 
|  | void | 
|  | DigitList::clear() | 
|  | { | 
|  | uprv_decNumberZero(fDecNumber); | 
|  | uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN); | 
|  | internalSetDouble(0.0); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Formats a int64_t number into a base 10 string representation, and NULL terminates it. | 
|  | * @param number The number to format | 
|  | * @param outputStr The string to output to.  Must be at least MAX_DIGITS+2 in length (21), | 
|  | *                  to hold the longest int64_t value. | 
|  | * @return the number of digits written, not including the sign. | 
|  | */ | 
|  | static int32_t | 
|  | formatBase10(int64_t number, char *outputStr) { | 
|  | // The number is output backwards, starting with the LSD. | 
|  | // Fill the buffer from the far end.  After the number is complete, | 
|  | // slide the string contents to the front. | 
|  |  | 
|  | const int32_t MAX_IDX = MAX_DIGITS+2; | 
|  | int32_t destIdx = MAX_IDX; | 
|  | outputStr[--destIdx] = 0; | 
|  |  | 
|  | int64_t  n = number; | 
|  | if (number < 0) {   // Negative numbers are slightly larger than a postive | 
|  | outputStr[--destIdx] = (char)(-(n % 10) + kZero); | 
|  | n /= -10; | 
|  | } | 
|  | do { | 
|  | outputStr[--destIdx] = (char)(n % 10 + kZero); | 
|  | n /= 10; | 
|  | } while (n > 0); | 
|  |  | 
|  | if (number < 0) { | 
|  | outputStr[--destIdx] = '-'; | 
|  | } | 
|  |  | 
|  | // Slide the number to the start of the output str | 
|  | U_ASSERT(destIdx >= 0); | 
|  | int32_t length = MAX_IDX - destIdx; | 
|  | uprv_memmove(outputStr, outputStr+MAX_IDX-length, length); | 
|  |  | 
|  | return length; | 
|  | } | 
|  |  | 
|  |  | 
|  | // ------------------------------------- | 
|  | // | 
|  | //  setRoundingMode() | 
|  | //    For most modes, the meaning and names are the same between the decNumber library | 
|  | //      (which DigitList follows) and the ICU Formatting Rounding Mode values. | 
|  | //      The flag constants are different, however. | 
|  | // | 
|  | //     Note that ICU's kRoundingUnnecessary is not implemented directly by DigitList. | 
|  | //     This mode, inherited from Java, means that numbers that would not format exactly | 
|  | //     will return an error when formatting is attempted. | 
|  |  | 
|  | void | 
|  | DigitList::setRoundingMode(DecimalFormat::ERoundingMode m) { | 
|  | enum rounding r; | 
|  |  | 
|  | switch (m) { | 
|  | case  DecimalFormat::kRoundCeiling:  r = DEC_ROUND_CEILING;   break; | 
|  | case  DecimalFormat::kRoundFloor:    r = DEC_ROUND_FLOOR;     break; | 
|  | case  DecimalFormat::kRoundDown:     r = DEC_ROUND_DOWN;      break; | 
|  | case  DecimalFormat::kRoundUp:       r = DEC_ROUND_UP;        break; | 
|  | case  DecimalFormat::kRoundHalfEven: r = DEC_ROUND_HALF_EVEN; break; | 
|  | case  DecimalFormat::kRoundHalfDown: r = DEC_ROUND_HALF_DOWN; break; | 
|  | case  DecimalFormat::kRoundHalfUp:   r = DEC_ROUND_HALF_UP;   break; | 
|  | case  DecimalFormat::kRoundUnnecessary: r = DEC_ROUND_HALF_EVEN; break; | 
|  | default: | 
|  | // TODO: how to report the problem? | 
|  | // Leave existing mode unchanged. | 
|  | r = uprv_decContextGetRounding(&fContext); | 
|  | } | 
|  | uprv_decContextSetRounding(&fContext, r); | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  | // ------------------------------------- | 
|  |  | 
|  | void | 
|  | DigitList::setPositive(UBool s) { | 
|  | if (s) { | 
|  | fDecNumber->bits &= ~DECNEG; | 
|  | } else { | 
|  | fDecNumber->bits |= DECNEG; | 
|  | } | 
|  | internalClear(); | 
|  | } | 
|  | // ------------------------------------- | 
|  |  | 
|  | void | 
|  | DigitList::setDecimalAt(int32_t d) { | 
|  | U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0);  // Not Infinity or NaN | 
|  | U_ASSERT(d-1>-999999999); | 
|  | U_ASSERT(d-1< 999999999); | 
|  | int32_t adjustedDigits = fDecNumber->digits; | 
|  | if (decNumberIsZero(fDecNumber)) { | 
|  | // Account for difference in how zero is represented between DigitList & decNumber. | 
|  | adjustedDigits = 0; | 
|  | } | 
|  | fDecNumber->exponent = d - adjustedDigits; | 
|  | internalClear(); | 
|  | } | 
|  |  | 
|  | int32_t | 
|  | DigitList::getDecimalAt() { | 
|  | U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0);  // Not Infinity or NaN | 
|  | if (decNumberIsZero(fDecNumber) || ((fDecNumber->bits & DECSPECIAL) != 0)) { | 
|  | return fDecNumber->exponent;  // Exponent should be zero for these cases. | 
|  | } | 
|  | return fDecNumber->exponent + fDecNumber->digits; | 
|  | } | 
|  |  | 
|  | void | 
|  | DigitList::setCount(int32_t c)  { | 
|  | U_ASSERT(c <= fContext.digits); | 
|  | if (c == 0) { | 
|  | // For a value of zero, DigitList sets all fields to zero, while | 
|  | // decNumber keeps one digit (with that digit being a zero) | 
|  | c = 1; | 
|  | fDecNumber->lsu[0] = 0; | 
|  | } | 
|  | fDecNumber->digits = c; | 
|  | internalClear(); | 
|  | } | 
|  |  | 
|  | int32_t | 
|  | DigitList::getCount() const { | 
|  | if (decNumberIsZero(fDecNumber) && fDecNumber->exponent==0) { | 
|  | // The extra test for exponent==0 is needed because parsing sometimes appends | 
|  | // zero digits.  It's bogus, decimalFormatter parsing needs to be cleaned up. | 
|  | return 0; | 
|  | } else { | 
|  | return fDecNumber->digits; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | DigitList::setDigit(int32_t i, char v) { | 
|  | int32_t count = fDecNumber->digits; | 
|  | U_ASSERT(i<count); | 
|  | U_ASSERT(v>='0' && v<='9'); | 
|  | v &= 0x0f; | 
|  | fDecNumber->lsu[count-i-1] = v; | 
|  | internalClear(); | 
|  | } | 
|  |  | 
|  | char | 
|  | DigitList::getDigit(int32_t i) { | 
|  | int32_t count = fDecNumber->digits; | 
|  | U_ASSERT(i<count); | 
|  | return fDecNumber->lsu[count-i-1] + '0'; | 
|  | } | 
|  |  | 
|  | // copied from DigitList::getDigit() | 
|  | uint8_t | 
|  | DigitList::getDigitValue(int32_t i) { | 
|  | int32_t count = fDecNumber->digits; | 
|  | U_ASSERT(i<count); | 
|  | return fDecNumber->lsu[count-i-1]; | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  | // Appends the digit to the digit list if it's not out of scope. | 
|  | // Ignores the digit, otherwise. | 
|  | // | 
|  | // This function is horribly inefficient to implement with decNumber because | 
|  | // the digits are stored least significant first, which requires moving all | 
|  | // existing digits down one to make space for the new one to be appended. | 
|  | // | 
|  | void | 
|  | DigitList::append(char digit) | 
|  | { | 
|  | U_ASSERT(digit>='0' && digit<='9'); | 
|  | // Ignore digits which exceed the precision we can represent | 
|  | //    And don't fix for larger precision.  Fix callers instead. | 
|  | if (decNumberIsZero(fDecNumber)) { | 
|  | // Zero needs to be special cased because of the difference in the way | 
|  | // that the old DigitList and decNumber represent it. | 
|  | // digit cout was zero for digitList, is one for decNumber | 
|  | fDecNumber->lsu[0] = digit & 0x0f; | 
|  | fDecNumber->digits = 1; | 
|  | fDecNumber->exponent--;     // To match the old digit list implementation. | 
|  | } else { | 
|  | int32_t nDigits = fDecNumber->digits; | 
|  | if (nDigits < fContext.digits) { | 
|  | int i; | 
|  | for (i=nDigits; i>0; i--) { | 
|  | fDecNumber->lsu[i] = fDecNumber->lsu[i-1]; | 
|  | } | 
|  | fDecNumber->lsu[0] = digit & 0x0f; | 
|  | fDecNumber->digits++; | 
|  | // DigitList emulation - appending doesn't change the magnitude of existing | 
|  | //                       digits.  With decNumber's decimal being after the | 
|  | //                       least signficant digit, we need to adjust the exponent. | 
|  | fDecNumber->exponent--; | 
|  | } | 
|  | } | 
|  | internalClear(); | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  |  | 
|  | /** | 
|  | * Currently, getDouble() depends on strtod() to do its conversion. | 
|  | * | 
|  | * WARNING!! | 
|  | * This is an extremely costly function. ~1/2 of the conversion time | 
|  | * can be linked to this function. | 
|  | */ | 
|  | double | 
|  | DigitList::getDouble() const | 
|  | { | 
|  | static char gDecimal = 0; | 
|  | char decimalSeparator; | 
|  | { | 
|  | Mutex mutex; | 
|  | if (fHave == kDouble) { | 
|  | return fUnion.fDouble; | 
|  | } else if(fHave == kInt64) { | 
|  | return (double)fUnion.fInt64; | 
|  | } | 
|  | decimalSeparator = gDecimal; | 
|  | } | 
|  |  | 
|  | if (decimalSeparator == 0) { | 
|  | // We need to know the decimal separator character that will be used with strtod(). | 
|  | // Depends on the C runtime global locale. | 
|  | // Most commonly is '.' | 
|  | // TODO: caching could fail if the global locale is changed on the fly. | 
|  | char rep[MAX_DIGITS]; | 
|  | sprintf(rep, "%+1.1f", 1.0); | 
|  | decimalSeparator = rep[2]; | 
|  | } | 
|  |  | 
|  | double tDouble = 0.0; | 
|  | if (isZero()) { | 
|  | tDouble = 0.0; | 
|  | if (decNumberIsNegative(fDecNumber)) { | 
|  | tDouble /= -1; | 
|  | } | 
|  | } else if (isInfinite()) { | 
|  | if (std::numeric_limits<double>::has_infinity) { | 
|  | tDouble = std::numeric_limits<double>::infinity(); | 
|  | } else { | 
|  | tDouble = std::numeric_limits<double>::max(); | 
|  | } | 
|  | if (!isPositive()) { | 
|  | tDouble = -tDouble; //this was incorrectly "-fDouble" originally. | 
|  | } | 
|  | } else { | 
|  | MaybeStackArray<char, MAX_DBL_DIGITS+18> s; | 
|  | // Note:  14 is a  magic constant from the decNumber library documentation, | 
|  | //        the max number of extra characters beyond the number of digits | 
|  | //        needed to represent the number in string form.  Add a few more | 
|  | //        for the additional digits we retain. | 
|  |  | 
|  | // Round down to appx. double precision, if the number is longer than that. | 
|  | // Copy the number first, so that we don't modify the original. | 
|  | if (getCount() > MAX_DBL_DIGITS + 3) { | 
|  | DigitList numToConvert(*this); | 
|  | numToConvert.reduce();    // Removes any trailing zeros, so that digit count is good. | 
|  | numToConvert.round(MAX_DBL_DIGITS+3); | 
|  | uprv_decNumberToString(numToConvert.fDecNumber, s.getAlias()); | 
|  | // TODO:  how many extra digits should be included for an accurate conversion? | 
|  | } else { | 
|  | uprv_decNumberToString(this->fDecNumber, s.getAlias()); | 
|  | } | 
|  | U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18); | 
|  |  | 
|  | if (decimalSeparator != '.') { | 
|  | char *decimalPt = strchr(s.getAlias(), '.'); | 
|  | if (decimalPt != NULL) { | 
|  | *decimalPt = decimalSeparator; | 
|  | } | 
|  | } | 
|  | char *end = NULL; | 
|  | tDouble = uprv_strtod(s.getAlias(), &end); | 
|  | } | 
|  | { | 
|  | Mutex mutex; | 
|  | DigitList *nonConstThis = const_cast<DigitList *>(this); | 
|  | nonConstThis->internalSetDouble(tDouble); | 
|  | gDecimal = decimalSeparator; | 
|  | } | 
|  | return tDouble; | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  |  | 
|  | /** | 
|  | *  convert this number to an int32_t.   Round if there is a fractional part. | 
|  | *  Return zero if the number cannot be represented. | 
|  | */ | 
|  | int32_t DigitList::getLong() /*const*/ | 
|  | { | 
|  | int32_t result = 0; | 
|  | if (fDecNumber->digits + fDecNumber->exponent > 10) { | 
|  | // Overflow, absolute value too big. | 
|  | return result; | 
|  | } | 
|  | if (fDecNumber->exponent != 0) { | 
|  | // Force to an integer, with zero exponent, rounding if necessary. | 
|  | //   (decNumberToInt32 will only work if the exponent is exactly zero.) | 
|  | DigitList copy(*this); | 
|  | DigitList zero; | 
|  | uprv_decNumberQuantize(copy.fDecNumber, copy.fDecNumber, zero.fDecNumber, &fContext); | 
|  | result = uprv_decNumberToInt32(copy.fDecNumber, &fContext); | 
|  | } else { | 
|  | result = uprv_decNumberToInt32(fDecNumber, &fContext); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | *  convert this number to an int64_t.   Truncate if there is a fractional part. | 
|  | *  Return zero if the number cannot be represented. | 
|  | */ | 
|  | int64_t DigitList::getInt64() /*const*/ { | 
|  | if(fHave==kInt64) { | 
|  | return fUnion.fInt64; | 
|  | } | 
|  | // Truncate if non-integer. | 
|  | // Return 0 if out of range. | 
|  | // Range of in64_t is -9223372036854775808 to 9223372036854775807  (19 digits) | 
|  | // | 
|  | if (fDecNumber->digits + fDecNumber->exponent > 19) { | 
|  | // Overflow, absolute value too big. | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | // The number of integer digits may differ from the number of digits stored | 
|  | //   in the decimal number. | 
|  | //     for 12.345  numIntDigits = 2, number->digits = 5 | 
|  | //     for 12E4    numIntDigits = 6, number->digits = 2 | 
|  | // The conversion ignores the fraction digits in the first case, | 
|  | // and fakes up extra zero digits in the second. | 
|  | // TODO:  It would be faster to store a table of powers of ten to multiply by | 
|  | //        instead of looping over zero digits, multiplying each time. | 
|  |  | 
|  | int32_t numIntDigits = fDecNumber->digits + fDecNumber->exponent; | 
|  | uint64_t value = 0; | 
|  | for (int32_t i = 0; i < numIntDigits; i++) { | 
|  | // Loop is iterating over digits starting with the most significant. | 
|  | // Numbers are stored with the least significant digit at index zero. | 
|  | int32_t digitIndex = fDecNumber->digits - i - 1; | 
|  | int32_t v = (digitIndex >= 0) ? fDecNumber->lsu[digitIndex] : 0; | 
|  | value = value * (uint64_t)10 + (uint64_t)v; | 
|  | } | 
|  |  | 
|  | if (decNumberIsNegative(fDecNumber)) { | 
|  | value = ~value; | 
|  | value += 1; | 
|  | } | 
|  | int64_t svalue = (int64_t)value; | 
|  |  | 
|  | // Check overflow.  It's convenient that the MSD is 9 only on overflow, the amount of | 
|  | //                  overflow can't wrap too far.  The test will also fail -0, but | 
|  | //                  that does no harm; the right answer is 0. | 
|  | if (numIntDigits == 19) { | 
|  | if (( decNumberIsNegative(fDecNumber) && svalue>0) || | 
|  | (!decNumberIsNegative(fDecNumber) && svalue<0)) { | 
|  | svalue = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | return svalue; | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | *  Return a string form of this number. | 
|  | *     Format is as defined by the decNumber library, for interchange of | 
|  | *     decimal numbers. | 
|  | */ | 
|  | void DigitList::getDecimal(CharString &str, UErrorCode &status) { | 
|  | if (U_FAILURE(status)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // A decimal number in string form can, worst case, be 14 characters longer | 
|  | //  than the number of digits.  So says the decNumber library doc. | 
|  | int32_t maxLength = fDecNumber->digits + 14; | 
|  | int32_t capacity = 0; | 
|  | char *buffer = str.clear().getAppendBuffer(maxLength, 0, capacity, status); | 
|  | if (U_FAILURE(status)) { | 
|  | return;    // Memory allocation error on growing the string. | 
|  | } | 
|  | U_ASSERT(capacity >= maxLength); | 
|  | uprv_decNumberToString(this->fDecNumber, buffer); | 
|  | U_ASSERT((int32_t)uprv_strlen(buffer) <= maxLength); | 
|  | str.append(buffer, -1, status); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return true if this is an integer value that can be held | 
|  | * by an int32_t type. | 
|  | */ | 
|  | UBool | 
|  | DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/ | 
|  | { | 
|  | if (decNumberIsSpecial(this->fDecNumber)) { | 
|  | // NaN or Infinity.  Does not fit in int32. | 
|  | return FALSE; | 
|  | } | 
|  | uprv_decNumberTrim(this->fDecNumber); | 
|  | if (fDecNumber->exponent < 0) { | 
|  | // Number contains fraction digits. | 
|  | return FALSE; | 
|  | } | 
|  | if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero && | 
|  | (fDecNumber->bits & DECNEG) != 0) { | 
|  | // Negative Zero, not ingored.  Cannot represent as a long. | 
|  | return FALSE; | 
|  | } | 
|  | if (fDecNumber->digits + fDecNumber->exponent < 10) { | 
|  | // The number is 9 or fewer digits. | 
|  | // The max and min int32 are 10 digts, so this number fits. | 
|  | // This is the common case. | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | // TODO:  Should cache these constants; construction is relatively costly. | 
|  | //        But not of huge consequence; they're only needed for 10 digit ints. | 
|  | UErrorCode status = U_ZERO_ERROR; | 
|  | DigitList min32; min32.set("-2147483648", status); | 
|  | if (this->compare(min32) < 0) { | 
|  | return FALSE; | 
|  | } | 
|  | DigitList max32; max32.set("2147483647", status); | 
|  | if (this->compare(max32) > 0) { | 
|  | return FALSE; | 
|  | } | 
|  | if (U_FAILURE(status)) { | 
|  | return FALSE; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /** | 
|  | * Return true if the number represented by this object can fit into | 
|  | * a long. | 
|  | */ | 
|  | UBool | 
|  | DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/ | 
|  | { | 
|  | if (decNumberIsSpecial(this->fDecNumber)) { | 
|  | // NaN or Infinity.  Does not fit in int32. | 
|  | return FALSE; | 
|  | } | 
|  | uprv_decNumberTrim(this->fDecNumber); | 
|  | if (fDecNumber->exponent < 0) { | 
|  | // Number contains fraction digits. | 
|  | return FALSE; | 
|  | } | 
|  | if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero && | 
|  | (fDecNumber->bits & DECNEG) != 0) { | 
|  | // Negative Zero, not ingored.  Cannot represent as a long. | 
|  | return FALSE; | 
|  | } | 
|  | if (fDecNumber->digits + fDecNumber->exponent < 19) { | 
|  | // The number is 18 or fewer digits. | 
|  | // The max and min int64 are 19 digts, so this number fits. | 
|  | // This is the common case. | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | // TODO:  Should cache these constants; construction is relatively costly. | 
|  | //        But not of huge consequence; they're only needed for 19 digit ints. | 
|  | UErrorCode status = U_ZERO_ERROR; | 
|  | DigitList min64; min64.set("-9223372036854775808", status); | 
|  | if (this->compare(min64) < 0) { | 
|  | return FALSE; | 
|  | } | 
|  | DigitList max64; max64.set("9223372036854775807", status); | 
|  | if (this->compare(max64) > 0) { | 
|  | return FALSE; | 
|  | } | 
|  | if (U_FAILURE(status)) { | 
|  | return FALSE; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  |  | 
|  | // ------------------------------------- | 
|  |  | 
|  | void | 
|  | DigitList::set(int32_t source) | 
|  | { | 
|  | set((int64_t)source); | 
|  | internalSetDouble(source); | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  | /** | 
|  | * Set an int64, via decnumber | 
|  | */ | 
|  | void | 
|  | DigitList::set(int64_t source) | 
|  | { | 
|  | char str[MAX_DIGITS+2];   // Leave room for sign and trailing nul. | 
|  | formatBase10(source, str); | 
|  | U_ASSERT(uprv_strlen(str) < sizeof(str)); | 
|  |  | 
|  | uprv_decNumberFromString(fDecNumber, str, &fContext); | 
|  | internalSetDouble(source); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set an int64, with no decnumber | 
|  | */ | 
|  | void | 
|  | DigitList::setInteger(int64_t source) | 
|  | { | 
|  | fDecNumber=NULL; | 
|  | internalSetInt64(source); | 
|  | } | 
|  |  | 
|  |  | 
|  | // ------------------------------------- | 
|  | /** | 
|  | * Set the DigitList from a decimal number string. | 
|  | * | 
|  | * The incoming string _must_ be nul terminated, even though it is arriving | 
|  | * as a StringPiece because that is what the decNumber library wants. | 
|  | * We can get away with this for an internal function; it would not | 
|  | * be acceptable for a public API. | 
|  | */ | 
|  | void | 
|  | DigitList::set(const StringPiece &source, UErrorCode &status, uint32_t /*fastpathBits*/) { | 
|  | if (U_FAILURE(status)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | #if 0 | 
|  | if(fastpathBits==(kFastpathOk|kNoDecimal)) { | 
|  | int32_t size = source.size(); | 
|  | const char *data = source.data(); | 
|  | int64_t r = 0; | 
|  | int64_t m = 1; | 
|  | // fast parse | 
|  | while(size>0) { | 
|  | char ch = data[--size]; | 
|  | if(ch=='+') { | 
|  | break; | 
|  | } else if(ch=='-') { | 
|  | r = -r; | 
|  | break; | 
|  | } else { | 
|  | int64_t d = ch-'0'; | 
|  | //printf("CH[%d]=%c, %d, *=%d\n", size,ch, (int)d, (int)m); | 
|  | r+=(d)*m; | 
|  | m *= 10; | 
|  | } | 
|  | } | 
|  | //printf("R=%d\n", r); | 
|  | set(r); | 
|  | } else | 
|  | #endif | 
|  | { | 
|  | // Figure out a max number of digits to use during the conversion, and | 
|  | // resize the number up if necessary. | 
|  | int32_t numDigits = source.length(); | 
|  | if (numDigits > fContext.digits) { | 
|  | // fContext.digits == fStorage.getCapacity() | 
|  | decNumber *t = fStorage.resize(numDigits, fStorage.getCapacity()); | 
|  | if (t == NULL) { | 
|  | status = U_MEMORY_ALLOCATION_ERROR; | 
|  | return; | 
|  | } | 
|  | fDecNumber = t; | 
|  | fContext.digits = numDigits; | 
|  | } | 
|  |  | 
|  | fContext.status = 0; | 
|  | uprv_decNumberFromString(fDecNumber, source.data(), &fContext); | 
|  | if ((fContext.status & DEC_Conversion_syntax) != 0) { | 
|  | status = U_DECIMAL_NUMBER_SYNTAX_ERROR; | 
|  | } | 
|  | } | 
|  | internalClear(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set the digit list to a representation of the given double value. | 
|  | * This method supports both fixed-point and exponential notation. | 
|  | * @param source Value to be converted. | 
|  | */ | 
|  | void | 
|  | DigitList::set(double source) | 
|  | { | 
|  | // for now, simple implementation; later, do proper IEEE stuff | 
|  | char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough) | 
|  |  | 
|  | // Generate a representation of the form /[+-][0-9].[0-9]+e[+-][0-9]+/ | 
|  | // Can also generate /[+-]nan/ or /[+-]inf/ | 
|  | // TODO: Use something other than sprintf() here, since it's behavior is somewhat platform specific. | 
|  | //       That is why infinity is special cased here. | 
|  | if (uprv_isInfinite(source)) { | 
|  | if (uprv_isNegativeInfinity(source)) { | 
|  | uprv_strcpy(rep,"-inf"); // Handle negative infinity | 
|  | } else { | 
|  | uprv_strcpy(rep,"inf"); | 
|  | } | 
|  | } else { | 
|  | sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source); | 
|  | } | 
|  | U_ASSERT(uprv_strlen(rep) < sizeof(rep)); | 
|  |  | 
|  | // uprv_decNumberFromString() will parse the string expecting '.' as a | 
|  | // decimal separator, however sprintf() can use ',' in certain locales. | 
|  | // Overwrite a ',' with '.' here before proceeding. | 
|  | char *decimalSeparator = strchr(rep, ','); | 
|  | if (decimalSeparator != NULL) { | 
|  | *decimalSeparator = '.'; | 
|  | } | 
|  |  | 
|  | // Create a decNumber from the string. | 
|  | uprv_decNumberFromString(fDecNumber, rep, &fContext); | 
|  | uprv_decNumberTrim(fDecNumber); | 
|  | internalSetDouble(source); | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  |  | 
|  | /* | 
|  | * Multiply | 
|  | *      The number will be expanded if need be to retain full precision. | 
|  | *      In practice, for formatting, multiply is by 10, 100 or 1000, so more digits | 
|  | *      will not be required for this use. | 
|  | */ | 
|  | void | 
|  | DigitList::mult(const DigitList &other, UErrorCode &status) { | 
|  | fContext.status = 0; | 
|  | int32_t requiredDigits = this->digits() + other.digits(); | 
|  | if (requiredDigits > fContext.digits) { | 
|  | reduce();    // Remove any trailing zeros | 
|  | int32_t requiredDigits = this->digits() + other.digits(); | 
|  | ensureCapacity(requiredDigits, status); | 
|  | } | 
|  | uprv_decNumberMultiply(fDecNumber, fDecNumber, other.fDecNumber, &fContext); | 
|  | internalClear(); | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  |  | 
|  | /* | 
|  | * Divide | 
|  | *      The number will _not_ be expanded for inexact results. | 
|  | *      TODO:  probably should expand some, for rounding increments that | 
|  | *             could add a few digits, e.g. .25, but not expand arbitrarily. | 
|  | */ | 
|  | void | 
|  | DigitList::div(const DigitList &other, UErrorCode &status) { | 
|  | if (U_FAILURE(status)) { | 
|  | return; | 
|  | } | 
|  | uprv_decNumberDivide(fDecNumber, fDecNumber, other.fDecNumber, &fContext); | 
|  | internalClear(); | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  |  | 
|  | /* | 
|  | * ensureCapacity.   Grow the digit storage for the number if it's less than the requested | 
|  | *         amount.  Never reduce it.  Available size is kept in fContext.digits. | 
|  | */ | 
|  | void | 
|  | DigitList::ensureCapacity(int32_t requestedCapacity, UErrorCode &status) { | 
|  | if (U_FAILURE(status)) { | 
|  | return; | 
|  | } | 
|  | if (requestedCapacity <= 0) { | 
|  | status = U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | } | 
|  | if (requestedCapacity > DEC_MAX_DIGITS) { | 
|  | // Don't report an error for requesting too much. | 
|  | // Arithemetic Results will be rounded to what can be supported. | 
|  | //   At 999,999,999 max digits, exceeding the limit is not too likely! | 
|  | requestedCapacity = DEC_MAX_DIGITS; | 
|  | } | 
|  | if (requestedCapacity > fContext.digits) { | 
|  | decNumber *newBuffer = fStorage.resize(requestedCapacity, fStorage.getCapacity()); | 
|  | if (newBuffer == NULL) { | 
|  | status = U_MEMORY_ALLOCATION_ERROR; | 
|  | return; | 
|  | } | 
|  | fContext.digits = requestedCapacity; | 
|  | fDecNumber = newBuffer; | 
|  | } | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  |  | 
|  | /** | 
|  | * Round the representation to the given number of digits. | 
|  | * @param maximumDigits The maximum number of digits to be shown. | 
|  | * Upon return, count will be less than or equal to maximumDigits. | 
|  | */ | 
|  | void | 
|  | DigitList::round(int32_t maximumDigits) | 
|  | { | 
|  | int32_t savedDigits  = fContext.digits; | 
|  | fContext.digits = maximumDigits; | 
|  | uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext); | 
|  | fContext.digits = savedDigits; | 
|  | uprv_decNumberTrim(fDecNumber); | 
|  | internalClear(); | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | DigitList::roundFixedPoint(int32_t maximumFractionDigits) { | 
|  | trim();        // Remove trailing zeros. | 
|  | if (fDecNumber->exponent >= -maximumFractionDigits) { | 
|  | return; | 
|  | } | 
|  | decNumber scale;   // Dummy decimal number, but with the desired number of | 
|  | uprv_decNumberZero(&scale);    //    fraction digits. | 
|  | scale.exponent = -maximumFractionDigits; | 
|  | scale.lsu[0] = 1; | 
|  |  | 
|  | uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext); | 
|  | trim(); | 
|  | internalClear(); | 
|  | } | 
|  |  | 
|  | // ------------------------------------- | 
|  |  | 
|  | void | 
|  | DigitList::toIntegralValue() { | 
|  | uprv_decNumberToIntegralValue(fDecNumber, fDecNumber, &fContext); | 
|  | } | 
|  |  | 
|  |  | 
|  | // ------------------------------------- | 
|  | UBool | 
|  | DigitList::isZero() const | 
|  | { | 
|  | return decNumberIsZero(fDecNumber); | 
|  | } | 
|  |  | 
|  | U_NAMESPACE_END | 
|  | #endif // #if !UCONFIG_NO_FORMATTING | 
|  |  | 
|  | //eof |