intl/icu/source/i18n/digitlst.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2 **********************************************************************
     3 *   Copyright (C) 1997-2012, International Business Machines
     4 *   Corporation and others.  All Rights Reserved.
     5 **********************************************************************
     6 *
     7 * File DIGITLST.CPP
     8 *
     9 * Modification History:
    10 *
    11 *   Date        Name        Description
    12 *   03/21/97    clhuang     Converted from java.
    13 *   03/21/97    clhuang     Implemented with new APIs.
    14 *   03/27/97    helena      Updated to pass the simple test after code review.
    15 *   03/31/97    aliu        Moved isLONG_MIN to here, and fixed it.
    16 *   04/15/97    aliu        Changed MAX_COUNT to DBL_DIG.  Changed Digit to char.
    17 *                           Reworked representation by replacing fDecimalAt
    18 *                           with fExponent.
    19 *   04/16/97    aliu        Rewrote set() and getDouble() to use sprintf/atof
    20 *                           to do digit conversion.
    21 *   09/09/97    aliu        Modified for exponential notation support.
    22 *   08/02/98    stephen     Added nearest/even rounding
    23 *                            Fixed bug in fitsIntoLong
    24 ******************************************************************************
    25 */
    27 #include "digitlst.h"
    29 #if !UCONFIG_NO_FORMATTING
    30 #include "unicode/putil.h"
    31 #include "charstr.h"
    32 #include "cmemory.h"
    33 #include "cstring.h"
    34 #include "mutex.h"
    35 #include "putilimp.h"
    36 #include "uassert.h"
    37 #include <stdlib.h>
    38 #include <limits.h>
    39 #include <string.h>
    40 #include <stdio.h>
    41 #include <limits>
    43 // ***************************************************************************
    44 // class DigitList
    45 //    A wrapper onto decNumber.
    46 //    Used to be standalone.
    47 // ***************************************************************************
    49 /**
    50  * This is the zero digit.  The base for the digits returned by getDigit()
    51  * Note that it is the platform invariant digit, and is not Unicode.
    52  */
    53 #define kZero '0'
    56 /* Only for 32 bit numbers. Ignore the negative sign. */
    57 //static const char LONG_MIN_REP[] = "2147483648";
    58 //static const char I64_MIN_REP[] = "9223372036854775808";
    61 static const uint8_t DIGIT_HAVE_NONE=0;
    62 static const uint8_t DIGIT_HAVE_DOUBLE=1;
    63 static const uint8_t DIGIT_HAVE_INT64=2;
    65 U_NAMESPACE_BEGIN
    67 // -------------------------------------
    68 // default constructor
    70 DigitList::DigitList()
    71 {
    72     uprv_decContextDefault(&fContext, DEC_INIT_BASE);
    73     fContext.traps  = 0;
    74     uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
    75     fContext.digits = fStorage.getCapacity();
    77     fDecNumber = fStorage.getAlias();
    78     uprv_decNumberZero(fDecNumber);
    80     internalSetDouble(0.0);
    81 }
    83 // -------------------------------------
    85 DigitList::~DigitList()
    86 {
    87 }
    89 // -------------------------------------
    90 // copy constructor
    92 DigitList::DigitList(const DigitList &other)
    93 {
    94     fDecNumber = fStorage.getAlias();
    95     *this = other;
    96 }
    99 // -------------------------------------
   100 // assignment operator
   102 DigitList&
   103 DigitList::operator=(const DigitList& other)
   104 {
   105     if (this != &other)
   106     {
   107         uprv_memcpy(&fContext, &other.fContext, sizeof(decContext));
   109         if (other.fStorage.getCapacity() > fStorage.getCapacity()) {
   110             fDecNumber = fStorage.resize(other.fStorage.getCapacity());
   111         }
   112         // Always reset the fContext.digits, even if fDecNumber was not reallocated,
   113         // because above we copied fContext from other.fContext.
   114         fContext.digits = fStorage.getCapacity();
   115         uprv_decNumberCopy(fDecNumber, other.fDecNumber);
   117         {
   118             // fDouble is lazily created and cached.
   119             // Avoid potential races with that happening with other.fDouble
   120             // while we are doing the assignment.
   121             Mutex mutex;
   123             if(other.fHave==kDouble) {
   124               fUnion.fDouble = other.fUnion.fDouble;
   125             } else if(other.fHave==kInt64) {
   126               fUnion.fInt64 = other.fUnion.fInt64;
   127             }
   128             fHave = other.fHave;
   129         }
   130     }
   131     return *this;
   132 }
   134 // -------------------------------------
   135 //    operator ==  (does not exactly match the old DigitList function)
   137 UBool
   138 DigitList::operator==(const DigitList& that) const
   139 {
   140     if (this == &that) {
   141         return TRUE;
   142     }
   143     decNumber n;  // Has space for only a none digit value.
   144     decContext c;
   145     uprv_decContextDefault(&c, DEC_INIT_BASE);
   146     c.digits = 1;
   147     c.traps = 0;
   149     uprv_decNumberCompare(&n, this->fDecNumber, that.fDecNumber, &c);
   150     UBool result = decNumberIsZero(&n);
   151     return result;
   152 }
   154 // -------------------------------------
   155 //      comparison function.   Returns 
   156 //         Not Comparable :  -2
   157 //                      < :  -1
   158 //                     == :   0
   159 //                      > :  +1
   160 int32_t DigitList::compare(const DigitList &other) {
   161     decNumber   result;
   162     int32_t     savedDigits = fContext.digits;
   163     fContext.digits = 1;
   164     uprv_decNumberCompare(&result, this->fDecNumber, other.fDecNumber, &fContext);
   165     fContext.digits = savedDigits;
   166     if (decNumberIsZero(&result)) {
   167         return 0;
   168     } else if (decNumberIsSpecial(&result)) {
   169         return -2;
   170     } else if (result.bits & DECNEG) {
   171         return -1;
   172     } else {
   173         return 1;
   174     }
   175 }
   178 // -------------------------------------
   179 //  Reduce - remove trailing zero digits.
   180 void
   181 DigitList::reduce() {
   182     uprv_decNumberReduce(fDecNumber, fDecNumber, &fContext);
   183 }
   186 // -------------------------------------
   187 //  trim - remove trailing fraction zero digits.
   188 void
   189 DigitList::trim() {
   190     uprv_decNumberTrim(fDecNumber);
   191 }
   193 // -------------------------------------
   194 // Resets the digit list; sets all the digits to zero.
   196 void
   197 DigitList::clear()
   198 {
   199     uprv_decNumberZero(fDecNumber);
   200     uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
   201     internalSetDouble(0.0);
   202 }
   205 /**
   206  * Formats a int64_t number into a base 10 string representation, and NULL terminates it.
   207  * @param number The number to format
   208  * @param outputStr The string to output to.  Must be at least MAX_DIGITS+2 in length (21),
   209  *                  to hold the longest int64_t value.
   210  * @return the number of digits written, not including the sign.
   211  */
   212 static int32_t
   213 formatBase10(int64_t number, char *outputStr) {
   214     // The number is output backwards, starting with the LSD.
   215     // Fill the buffer from the far end.  After the number is complete,
   216     // slide the string contents to the front.
   218     const int32_t MAX_IDX = MAX_DIGITS+2;
   219     int32_t destIdx = MAX_IDX;
   220     outputStr[--destIdx] = 0; 
   222     int64_t  n = number;
   223     if (number < 0) {   // Negative numbers are slightly larger than a postive
   224         outputStr[--destIdx] = (char)(-(n % 10) + kZero);
   225         n /= -10;
   226     }
   227     do { 
   228         outputStr[--destIdx] = (char)(n % 10 + kZero);
   229         n /= 10;
   230     } while (n > 0);
   232     if (number < 0) {
   233         outputStr[--destIdx] = '-';
   234     }
   236     // Slide the number to the start of the output str
   237     U_ASSERT(destIdx >= 0);
   238     int32_t length = MAX_IDX - destIdx;
   239     uprv_memmove(outputStr, outputStr+MAX_IDX-length, length);
   241     return length;
   242 }
   245 // -------------------------------------
   246 //
   247 //  setRoundingMode()
   248 //    For most modes, the meaning and names are the same between the decNumber library
   249 //      (which DigitList follows) and the ICU Formatting Rounding Mode values.
   250 //      The flag constants are different, however.
   251 //
   252 //     Note that ICU's kRoundingUnnecessary is not implemented directly by DigitList.
   253 //     This mode, inherited from Java, means that numbers that would not format exactly
   254 //     will return an error when formatting is attempted.
   256 void 
   257 DigitList::setRoundingMode(DecimalFormat::ERoundingMode m) {
   258     enum rounding r;
   260     switch (m) {
   261       case  DecimalFormat::kRoundCeiling:  r = DEC_ROUND_CEILING;   break;
   262       case  DecimalFormat::kRoundFloor:    r = DEC_ROUND_FLOOR;     break;
   263       case  DecimalFormat::kRoundDown:     r = DEC_ROUND_DOWN;      break;
   264       case  DecimalFormat::kRoundUp:       r = DEC_ROUND_UP;        break;
   265       case  DecimalFormat::kRoundHalfEven: r = DEC_ROUND_HALF_EVEN; break;
   266       case  DecimalFormat::kRoundHalfDown: r = DEC_ROUND_HALF_DOWN; break;
   267       case  DecimalFormat::kRoundHalfUp:   r = DEC_ROUND_HALF_UP;   break;
   268       case  DecimalFormat::kRoundUnnecessary: r = DEC_ROUND_HALF_EVEN; break;
   269       default:
   270          // TODO: how to report the problem?
   271          // Leave existing mode unchanged.
   272          r = uprv_decContextGetRounding(&fContext);
   273     }
   274     uprv_decContextSetRounding(&fContext, r);
   276 }
   279 // -------------------------------------
   281 void  
   282 DigitList::setPositive(UBool s) {
   283     if (s) {
   284         fDecNumber->bits &= ~DECNEG; 
   285     } else {
   286         fDecNumber->bits |= DECNEG;
   287     }
   288     internalClear();
   289 }
   290 // -------------------------------------
   292 void     
   293 DigitList::setDecimalAt(int32_t d) {
   294     U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0);  // Not Infinity or NaN
   295     U_ASSERT(d-1>-999999999);
   296     U_ASSERT(d-1< 999999999);
   297     int32_t adjustedDigits = fDecNumber->digits;
   298     if (decNumberIsZero(fDecNumber)) {
   299         // Account for difference in how zero is represented between DigitList & decNumber.
   300         adjustedDigits = 0;
   301     }
   302     fDecNumber->exponent = d - adjustedDigits;
   303     internalClear();
   304 }
   306 int32_t  
   307 DigitList::getDecimalAt() {
   308     U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0);  // Not Infinity or NaN
   309     if (decNumberIsZero(fDecNumber) || ((fDecNumber->bits & DECSPECIAL) != 0)) {
   310         return fDecNumber->exponent;  // Exponent should be zero for these cases.
   311     }
   312     return fDecNumber->exponent + fDecNumber->digits;
   313 }
   315 void     
   316 DigitList::setCount(int32_t c)  {
   317     U_ASSERT(c <= fContext.digits);
   318     if (c == 0) {
   319         // For a value of zero, DigitList sets all fields to zero, while
   320         // decNumber keeps one digit (with that digit being a zero)
   321         c = 1;
   322         fDecNumber->lsu[0] = 0;
   323     }
   324     fDecNumber->digits = c;
   325     internalClear();
   326 }
   328 int32_t  
   329 DigitList::getCount() const {
   330     if (decNumberIsZero(fDecNumber) && fDecNumber->exponent==0) {
   331        // The extra test for exponent==0 is needed because parsing sometimes appends
   332        // zero digits.  It's bogus, decimalFormatter parsing needs to be cleaned up.
   333        return 0;
   334     } else {
   335        return fDecNumber->digits;
   336     }
   337 }
   339 void     
   340 DigitList::setDigit(int32_t i, char v) {
   341     int32_t count = fDecNumber->digits;
   342     U_ASSERT(i<count);
   343     U_ASSERT(v>='0' && v<='9');
   344     v &= 0x0f;
   345     fDecNumber->lsu[count-i-1] = v;
   346     internalClear();
   347 }
   349 char     
   350 DigitList::getDigit(int32_t i) {
   351     int32_t count = fDecNumber->digits;
   352     U_ASSERT(i<count);
   353     return fDecNumber->lsu[count-i-1] + '0';
   354 }
   356 // copied from DigitList::getDigit()
   357 uint8_t
   358 DigitList::getDigitValue(int32_t i) {
   359     int32_t count = fDecNumber->digits;
   360     U_ASSERT(i<count);
   361     return fDecNumber->lsu[count-i-1];
   362 }
   364 // -------------------------------------
   365 // Appends the digit to the digit list if it's not out of scope.
   366 // Ignores the digit, otherwise.
   367 // 
   368 // This function is horribly inefficient to implement with decNumber because
   369 // the digits are stored least significant first, which requires moving all
   370 // existing digits down one to make space for the new one to be appended.
   371 //
   372 void
   373 DigitList::append(char digit)
   374 {
   375     U_ASSERT(digit>='0' && digit<='9');
   376     // Ignore digits which exceed the precision we can represent
   377     //    And don't fix for larger precision.  Fix callers instead.
   378     if (decNumberIsZero(fDecNumber)) {
   379         // Zero needs to be special cased because of the difference in the way
   380         // that the old DigitList and decNumber represent it.
   381         // digit cout was zero for digitList, is one for decNumber
   382         fDecNumber->lsu[0] = digit & 0x0f;
   383         fDecNumber->digits = 1;
   384         fDecNumber->exponent--;     // To match the old digit list implementation.
   385     } else {
   386         int32_t nDigits = fDecNumber->digits;
   387         if (nDigits < fContext.digits) {
   388             int i;
   389             for (i=nDigits; i>0; i--) {
   390                 fDecNumber->lsu[i] = fDecNumber->lsu[i-1];
   391             }
   392             fDecNumber->lsu[0] = digit & 0x0f;
   393             fDecNumber->digits++;
   394             // DigitList emulation - appending doesn't change the magnitude of existing
   395             //                       digits.  With decNumber's decimal being after the
   396             //                       least signficant digit, we need to adjust the exponent.
   397             fDecNumber->exponent--;
   398         }
   399     }
   400     internalClear();
   401 }
   403 // -------------------------------------
   405 /**
   406  * Currently, getDouble() depends on strtod() to do its conversion.
   407  *
   408  * WARNING!!
   409  * This is an extremely costly function. ~1/2 of the conversion time
   410  * can be linked to this function.
   411  */
   412 double
   413 DigitList::getDouble() const
   414 {
   415     static char gDecimal = 0;
   416     char decimalSeparator;
   417     {
   418         Mutex mutex;
   419         if (fHave == kDouble) {
   420             return fUnion.fDouble;
   421         } else if(fHave == kInt64) {
   422             return (double)fUnion.fInt64;
   423         }
   424         decimalSeparator = gDecimal;
   425     }
   427     if (decimalSeparator == 0) {
   428         // We need to know the decimal separator character that will be used with strtod().
   429         // Depends on the C runtime global locale.
   430         // Most commonly is '.'
   431         // TODO: caching could fail if the global locale is changed on the fly.
   432         char rep[MAX_DIGITS];
   433         sprintf(rep, "%+1.1f", 1.0);
   434         decimalSeparator = rep[2];
   435     }
   437     double tDouble = 0.0;
   438     if (isZero()) {
   439         tDouble = 0.0;
   440         if (decNumberIsNegative(fDecNumber)) {
   441             tDouble /= -1;
   442         }
   443     } else if (isInfinite()) {
   444         if (std::numeric_limits<double>::has_infinity) {
   445             tDouble = std::numeric_limits<double>::infinity();
   446         } else {
   447             tDouble = std::numeric_limits<double>::max();
   448         }
   449         if (!isPositive()) {
   450             tDouble = -tDouble; //this was incorrectly "-fDouble" originally.
   451         } 
   452     } else {
   453         MaybeStackArray<char, MAX_DBL_DIGITS+18> s;
   454            // Note:  14 is a  magic constant from the decNumber library documentation,
   455            //        the max number of extra characters beyond the number of digits 
   456            //        needed to represent the number in string form.  Add a few more
   457            //        for the additional digits we retain.
   459         // Round down to appx. double precision, if the number is longer than that.
   460         // Copy the number first, so that we don't modify the original.
   461         if (getCount() > MAX_DBL_DIGITS + 3) {
   462             DigitList numToConvert(*this);
   463             numToConvert.reduce();    // Removes any trailing zeros, so that digit count is good.
   464             numToConvert.round(MAX_DBL_DIGITS+3);
   465             uprv_decNumberToString(numToConvert.fDecNumber, s.getAlias());
   466             // TODO:  how many extra digits should be included for an accurate conversion?
   467         } else {
   468             uprv_decNumberToString(this->fDecNumber, s.getAlias());
   469         }
   470         U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18);
   472         if (decimalSeparator != '.') {
   473             char *decimalPt = strchr(s.getAlias(), '.');
   474             if (decimalPt != NULL) {
   475                 *decimalPt = decimalSeparator;
   476             }
   477         }
   478         char *end = NULL;
   479         tDouble = uprv_strtod(s.getAlias(), &end);
   480     }
   481     {
   482         Mutex mutex;
   483         DigitList *nonConstThis = const_cast<DigitList *>(this);
   484         nonConstThis->internalSetDouble(tDouble);
   485         gDecimal = decimalSeparator;
   486     }
   487     return tDouble;
   488 }
   490 // -------------------------------------
   492 /**
   493  *  convert this number to an int32_t.   Round if there is a fractional part.
   494  *  Return zero if the number cannot be represented.
   495  */
   496 int32_t DigitList::getLong() /*const*/
   497 {
   498     int32_t result = 0;
   499     if (fDecNumber->digits + fDecNumber->exponent > 10) {
   500         // Overflow, absolute value too big.
   501         return result;
   502     }
   503     if (fDecNumber->exponent != 0) {
   504         // Force to an integer, with zero exponent, rounding if necessary.
   505         //   (decNumberToInt32 will only work if the exponent is exactly zero.)
   506         DigitList copy(*this);
   507         DigitList zero;
   508         uprv_decNumberQuantize(copy.fDecNumber, copy.fDecNumber, zero.fDecNumber, &fContext);
   509         result = uprv_decNumberToInt32(copy.fDecNumber, &fContext);
   510     } else {
   511         result = uprv_decNumberToInt32(fDecNumber, &fContext);
   512     }
   513     return result;
   514 }
   517 /**
   518  *  convert this number to an int64_t.   Truncate if there is a fractional part.
   519  *  Return zero if the number cannot be represented.
   520  */
   521 int64_t DigitList::getInt64() /*const*/ {
   522     if(fHave==kInt64) {
   523       return fUnion.fInt64;
   524     } 
   525     // Truncate if non-integer.
   526     // Return 0 if out of range.
   527     // Range of in64_t is -9223372036854775808 to 9223372036854775807  (19 digits)
   528     //
   529     if (fDecNumber->digits + fDecNumber->exponent > 19) {
   530         // Overflow, absolute value too big.
   531         return 0;
   532     }
   534     // The number of integer digits may differ from the number of digits stored
   535     //   in the decimal number.
   536     //     for 12.345  numIntDigits = 2, number->digits = 5
   537     //     for 12E4    numIntDigits = 6, number->digits = 2
   538     // The conversion ignores the fraction digits in the first case,
   539     // and fakes up extra zero digits in the second.
   540     // TODO:  It would be faster to store a table of powers of ten to multiply by
   541     //        instead of looping over zero digits, multiplying each time.
   543     int32_t numIntDigits = fDecNumber->digits + fDecNumber->exponent;
   544     uint64_t value = 0;
   545     for (int32_t i = 0; i < numIntDigits; i++) {
   546         // Loop is iterating over digits starting with the most significant.
   547         // Numbers are stored with the least significant digit at index zero.
   548         int32_t digitIndex = fDecNumber->digits - i - 1;
   549         int32_t v = (digitIndex >= 0) ? fDecNumber->lsu[digitIndex] : 0;
   550         value = value * (uint64_t)10 + (uint64_t)v;
   551     }
   553     if (decNumberIsNegative(fDecNumber)) {
   554         value = ~value;
   555         value += 1;
   556     }
   557     int64_t svalue = (int64_t)value;
   559     // Check overflow.  It's convenient that the MSD is 9 only on overflow, the amount of
   560     //                  overflow can't wrap too far.  The test will also fail -0, but
   561     //                  that does no harm; the right answer is 0.
   562     if (numIntDigits == 19) {
   563         if (( decNumberIsNegative(fDecNumber) && svalue>0) ||
   564             (!decNumberIsNegative(fDecNumber) && svalue<0)) {
   565             svalue = 0;
   566         }
   567     }
   569     return svalue;
   570 }
   573 /**
   574  *  Return a string form of this number.
   575  *     Format is as defined by the decNumber library, for interchange of
   576  *     decimal numbers.
   577  */
   578 void DigitList::getDecimal(CharString &str, UErrorCode &status) {
   579     if (U_FAILURE(status)) {
   580         return;
   581     }
   583     // A decimal number in string form can, worst case, be 14 characters longer
   584     //  than the number of digits.  So says the decNumber library doc.
   585     int32_t maxLength = fDecNumber->digits + 14;
   586     int32_t capacity = 0;
   587     char *buffer = str.clear().getAppendBuffer(maxLength, 0, capacity, status);
   588     if (U_FAILURE(status)) {
   589         return;    // Memory allocation error on growing the string.
   590     }
   591     U_ASSERT(capacity >= maxLength);
   592     uprv_decNumberToString(this->fDecNumber, buffer);
   593     U_ASSERT((int32_t)uprv_strlen(buffer) <= maxLength);
   594     str.append(buffer, -1, status);
   595 }
   597 /**
   598  * Return true if this is an integer value that can be held
   599  * by an int32_t type.
   600  */
   601 UBool
   602 DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/
   603 {
   604     if (decNumberIsSpecial(this->fDecNumber)) {
   605         // NaN or Infinity.  Does not fit in int32.
   606         return FALSE;
   607     }
   608     uprv_decNumberTrim(this->fDecNumber);
   609     if (fDecNumber->exponent < 0) {
   610         // Number contains fraction digits.
   611         return FALSE;
   612     }
   613     if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
   614         (fDecNumber->bits & DECNEG) != 0) {
   615         // Negative Zero, not ingored.  Cannot represent as a long.
   616         return FALSE;
   617     }
   618     if (fDecNumber->digits + fDecNumber->exponent < 10) {
   619         // The number is 9 or fewer digits.
   620         // The max and min int32 are 10 digts, so this number fits.
   621         // This is the common case.
   622         return TRUE;
   623     }
   625     // TODO:  Should cache these constants; construction is relatively costly.
   626     //        But not of huge consequence; they're only needed for 10 digit ints.
   627     UErrorCode status = U_ZERO_ERROR;
   628     DigitList min32; min32.set("-2147483648", status);
   629     if (this->compare(min32) < 0) {
   630         return FALSE;
   631     }
   632     DigitList max32; max32.set("2147483647", status);
   633     if (this->compare(max32) > 0) {
   634         return FALSE;
   635     }
   636     if (U_FAILURE(status)) {
   637         return FALSE;
   638     }
   639     return true;
   640 }
   644 /**
   645  * Return true if the number represented by this object can fit into
   646  * a long.
   647  */
   648 UBool
   649 DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/
   650 {
   651     if (decNumberIsSpecial(this->fDecNumber)) {
   652         // NaN or Infinity.  Does not fit in int32.
   653         return FALSE;
   654     }
   655     uprv_decNumberTrim(this->fDecNumber);
   656     if (fDecNumber->exponent < 0) {
   657         // Number contains fraction digits.
   658         return FALSE;
   659     }
   660     if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
   661         (fDecNumber->bits & DECNEG) != 0) {
   662         // Negative Zero, not ingored.  Cannot represent as a long.
   663         return FALSE;
   664     }
   665     if (fDecNumber->digits + fDecNumber->exponent < 19) {
   666         // The number is 18 or fewer digits.
   667         // The max and min int64 are 19 digts, so this number fits.
   668         // This is the common case.
   669         return TRUE;
   670     }
   672     // TODO:  Should cache these constants; construction is relatively costly.
   673     //        But not of huge consequence; they're only needed for 19 digit ints.
   674     UErrorCode status = U_ZERO_ERROR;
   675     DigitList min64; min64.set("-9223372036854775808", status);
   676     if (this->compare(min64) < 0) {
   677         return FALSE;
   678     }
   679     DigitList max64; max64.set("9223372036854775807", status);
   680     if (this->compare(max64) > 0) {
   681         return FALSE;
   682     }
   683     if (U_FAILURE(status)) {
   684         return FALSE;
   685     }
   686     return true;
   687 }
   690 // -------------------------------------
   692 void
   693 DigitList::set(int32_t source)
   694 {
   695     set((int64_t)source);
   696     internalSetDouble(source);
   697 }
   699 // -------------------------------------
   700 /**
   701  * Set an int64, via decnumber
   702  */
   703 void
   704 DigitList::set(int64_t source)
   705 {
   706     char str[MAX_DIGITS+2];   // Leave room for sign and trailing nul.
   707     formatBase10(source, str);
   708     U_ASSERT(uprv_strlen(str) < sizeof(str));
   710     uprv_decNumberFromString(fDecNumber, str, &fContext);
   711     internalSetDouble(source);
   712 }
   714 /**
   715  * Set an int64, with no decnumber
   716  */
   717 void
   718 DigitList::setInteger(int64_t source)
   719 {
   720   fDecNumber=NULL;
   721   internalSetInt64(source);
   722 }
   725 // -------------------------------------
   726 /**
   727  * Set the DigitList from a decimal number string.
   728  *
   729  * The incoming string _must_ be nul terminated, even though it is arriving
   730  * as a StringPiece because that is what the decNumber library wants.
   731  * We can get away with this for an internal function; it would not
   732  * be acceptable for a public API.
   733  */
   734 void
   735 DigitList::set(const StringPiece &source, UErrorCode &status, uint32_t /*fastpathBits*/) {
   736     if (U_FAILURE(status)) {
   737         return;
   738     }
   740 #if 0    
   741     if(fastpathBits==(kFastpathOk|kNoDecimal)) {
   742       int32_t size = source.size();
   743       const char *data = source.data();
   744       int64_t r = 0;
   745       int64_t m = 1;
   746       // fast parse
   747       while(size>0) {
   748         char ch = data[--size];
   749         if(ch=='+') {
   750           break;
   751         } else if(ch=='-') {
   752           r = -r;
   753           break;
   754         } else {
   755           int64_t d = ch-'0';
   756           //printf("CH[%d]=%c, %d, *=%d\n", size,ch, (int)d, (int)m);
   757           r+=(d)*m;
   758           m *= 10;
   759         }
   760       }
   761       //printf("R=%d\n", r);
   762       set(r);
   763     } else
   764 #endif
   765         {
   766       // Figure out a max number of digits to use during the conversion, and
   767       // resize the number up if necessary.
   768       int32_t numDigits = source.length();
   769       if (numDigits > fContext.digits) {
   770         // fContext.digits == fStorage.getCapacity()
   771         decNumber *t = fStorage.resize(numDigits, fStorage.getCapacity());
   772         if (t == NULL) {
   773           status = U_MEMORY_ALLOCATION_ERROR;
   774           return;
   775         }
   776         fDecNumber = t;
   777         fContext.digits = numDigits;
   778       }
   780       fContext.status = 0;
   781       uprv_decNumberFromString(fDecNumber, source.data(), &fContext);
   782       if ((fContext.status & DEC_Conversion_syntax) != 0) {
   783         status = U_DECIMAL_NUMBER_SYNTAX_ERROR;
   784       }
   785     }
   786     internalClear();
   787 }   
   789 /**
   790  * Set the digit list to a representation of the given double value.
   791  * This method supports both fixed-point and exponential notation.
   792  * @param source Value to be converted.
   793  */
   794 void
   795 DigitList::set(double source)
   796 {
   797     // for now, simple implementation; later, do proper IEEE stuff
   798     char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough)
   800     // Generate a representation of the form /[+-][0-9].[0-9]+e[+-][0-9]+/
   801     // Can also generate /[+-]nan/ or /[+-]inf/
   802     // TODO: Use something other than sprintf() here, since it's behavior is somewhat platform specific.
   803     //       That is why infinity is special cased here.
   804     if (uprv_isInfinite(source)) {
   805         if (uprv_isNegativeInfinity(source)) {
   806             uprv_strcpy(rep,"-inf"); // Handle negative infinity
   807         } else {
   808             uprv_strcpy(rep,"inf");
   809         }
   810     } else {
   811         sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source);
   812     }
   813     U_ASSERT(uprv_strlen(rep) < sizeof(rep));
   815     // uprv_decNumberFromString() will parse the string expecting '.' as a
   816     // decimal separator, however sprintf() can use ',' in certain locales.
   817     // Overwrite a ',' with '.' here before proceeding.
   818     char *decimalSeparator = strchr(rep, ',');
   819     if (decimalSeparator != NULL) {
   820         *decimalSeparator = '.';
   821     }
   823     // Create a decNumber from the string.
   824     uprv_decNumberFromString(fDecNumber, rep, &fContext);
   825     uprv_decNumberTrim(fDecNumber);
   826     internalSetDouble(source);
   827 }
   829 // -------------------------------------
   831 /*
   832  * Multiply
   833  *      The number will be expanded if need be to retain full precision.
   834  *      In practice, for formatting, multiply is by 10, 100 or 1000, so more digits
   835  *      will not be required for this use.
   836  */
   837 void
   838 DigitList::mult(const DigitList &other, UErrorCode &status) {
   839     fContext.status = 0;
   840     int32_t requiredDigits = this->digits() + other.digits();
   841     if (requiredDigits > fContext.digits) {
   842         reduce();    // Remove any trailing zeros
   843         int32_t requiredDigits = this->digits() + other.digits();
   844         ensureCapacity(requiredDigits, status);
   845     }
   846     uprv_decNumberMultiply(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
   847     internalClear();
   848 }
   850 // -------------------------------------
   852 /*
   853  * Divide
   854  *      The number will _not_ be expanded for inexact results.
   855  *      TODO:  probably should expand some, for rounding increments that
   856  *             could add a few digits, e.g. .25, but not expand arbitrarily.
   857  */
   858 void
   859 DigitList::div(const DigitList &other, UErrorCode &status) {
   860     if (U_FAILURE(status)) {
   861         return;
   862     }
   863     uprv_decNumberDivide(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
   864     internalClear();
   865 }
   867 // -------------------------------------
   869 /*
   870  * ensureCapacity.   Grow the digit storage for the number if it's less than the requested
   871  *         amount.  Never reduce it.  Available size is kept in fContext.digits.
   872  */
   873 void
   874 DigitList::ensureCapacity(int32_t requestedCapacity, UErrorCode &status) {
   875     if (U_FAILURE(status)) {
   876         return;
   877     }
   878     if (requestedCapacity <= 0) {
   879         status = U_ILLEGAL_ARGUMENT_ERROR;
   880         return;
   881     }
   882     if (requestedCapacity > DEC_MAX_DIGITS) {
   883         // Don't report an error for requesting too much.
   884         // Arithemetic Results will be rounded to what can be supported.
   885         //   At 999,999,999 max digits, exceeding the limit is not too likely!
   886         requestedCapacity = DEC_MAX_DIGITS;
   887     }
   888     if (requestedCapacity > fContext.digits) {
   889         decNumber *newBuffer = fStorage.resize(requestedCapacity, fStorage.getCapacity());
   890         if (newBuffer == NULL) {
   891             status = U_MEMORY_ALLOCATION_ERROR;
   892             return;
   893         }
   894         fContext.digits = requestedCapacity;
   895         fDecNumber = newBuffer;
   896     }
   897 }
   899 // -------------------------------------
   901 /**
   902  * Round the representation to the given number of digits.
   903  * @param maximumDigits The maximum number of digits to be shown.
   904  * Upon return, count will be less than or equal to maximumDigits.
   905  */
   906 void
   907 DigitList::round(int32_t maximumDigits)
   908 {
   909     int32_t savedDigits  = fContext.digits;
   910     fContext.digits = maximumDigits;
   911     uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext);
   912     fContext.digits = savedDigits;
   913     uprv_decNumberTrim(fDecNumber);
   914     internalClear();
   915 }
   918 void
   919 DigitList::roundFixedPoint(int32_t maximumFractionDigits) {
   920     trim();        // Remove trailing zeros.
   921     if (fDecNumber->exponent >= -maximumFractionDigits) {
   922         return;
   923     }
   924     decNumber scale;   // Dummy decimal number, but with the desired number of
   925     uprv_decNumberZero(&scale);    //    fraction digits.
   926     scale.exponent = -maximumFractionDigits;
   927     scale.lsu[0] = 1;
   929     uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext);
   930     trim();
   931     internalClear();
   932 }
   934 // -------------------------------------
   936 void
   937 DigitList::toIntegralValue() {
   938     uprv_decNumberToIntegralValue(fDecNumber, fDecNumber, &fContext);
   939 }
   942 // -------------------------------------
   943 UBool
   944 DigitList::isZero() const
   945 {
   946     return decNumberIsZero(fDecNumber);
   947 }
   949 U_NAMESPACE_END
   950 #endif // #if !UCONFIG_NO_FORMATTING
   952 //eof

mercurial