intl/icu/source/i18n/digitlst.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/i18n/digitlst.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,952 @@
     1.4 +/*
     1.5 +**********************************************************************
     1.6 +*   Copyright (C) 1997-2012, International Business Machines
     1.7 +*   Corporation and others.  All Rights Reserved.
     1.8 +**********************************************************************
     1.9 +*
    1.10 +* File DIGITLST.CPP
    1.11 +*
    1.12 +* Modification History:
    1.13 +*
    1.14 +*   Date        Name        Description
    1.15 +*   03/21/97    clhuang     Converted from java.
    1.16 +*   03/21/97    clhuang     Implemented with new APIs.
    1.17 +*   03/27/97    helena      Updated to pass the simple test after code review.
    1.18 +*   03/31/97    aliu        Moved isLONG_MIN to here, and fixed it.
    1.19 +*   04/15/97    aliu        Changed MAX_COUNT to DBL_DIG.  Changed Digit to char.
    1.20 +*                           Reworked representation by replacing fDecimalAt
    1.21 +*                           with fExponent.
    1.22 +*   04/16/97    aliu        Rewrote set() and getDouble() to use sprintf/atof
    1.23 +*                           to do digit conversion.
    1.24 +*   09/09/97    aliu        Modified for exponential notation support.
    1.25 +*   08/02/98    stephen     Added nearest/even rounding
    1.26 +*                            Fixed bug in fitsIntoLong
    1.27 +******************************************************************************
    1.28 +*/
    1.29 +
    1.30 +#include "digitlst.h"
    1.31 +
    1.32 +#if !UCONFIG_NO_FORMATTING
    1.33 +#include "unicode/putil.h"
    1.34 +#include "charstr.h"
    1.35 +#include "cmemory.h"
    1.36 +#include "cstring.h"
    1.37 +#include "mutex.h"
    1.38 +#include "putilimp.h"
    1.39 +#include "uassert.h"
    1.40 +#include <stdlib.h>
    1.41 +#include <limits.h>
    1.42 +#include <string.h>
    1.43 +#include <stdio.h>
    1.44 +#include <limits>
    1.45 +
    1.46 +// ***************************************************************************
    1.47 +// class DigitList
    1.48 +//    A wrapper onto decNumber.
    1.49 +//    Used to be standalone.
    1.50 +// ***************************************************************************
    1.51 +
    1.52 +/**
    1.53 + * This is the zero digit.  The base for the digits returned by getDigit()
    1.54 + * Note that it is the platform invariant digit, and is not Unicode.
    1.55 + */
    1.56 +#define kZero '0'
    1.57 +
    1.58 +
    1.59 +/* Only for 32 bit numbers. Ignore the negative sign. */
    1.60 +//static const char LONG_MIN_REP[] = "2147483648";
    1.61 +//static const char I64_MIN_REP[] = "9223372036854775808";
    1.62 +
    1.63 +
    1.64 +static const uint8_t DIGIT_HAVE_NONE=0;
    1.65 +static const uint8_t DIGIT_HAVE_DOUBLE=1;
    1.66 +static const uint8_t DIGIT_HAVE_INT64=2;
    1.67 +
    1.68 +U_NAMESPACE_BEGIN
    1.69 +
    1.70 +// -------------------------------------
    1.71 +// default constructor
    1.72 +
    1.73 +DigitList::DigitList()
    1.74 +{
    1.75 +    uprv_decContextDefault(&fContext, DEC_INIT_BASE);
    1.76 +    fContext.traps  = 0;
    1.77 +    uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
    1.78 +    fContext.digits = fStorage.getCapacity();
    1.79 +
    1.80 +    fDecNumber = fStorage.getAlias();
    1.81 +    uprv_decNumberZero(fDecNumber);
    1.82 +
    1.83 +    internalSetDouble(0.0);
    1.84 +}
    1.85 +
    1.86 +// -------------------------------------
    1.87 +
    1.88 +DigitList::~DigitList()
    1.89 +{
    1.90 +}
    1.91 +
    1.92 +// -------------------------------------
    1.93 +// copy constructor
    1.94 +
    1.95 +DigitList::DigitList(const DigitList &other)
    1.96 +{
    1.97 +    fDecNumber = fStorage.getAlias();
    1.98 +    *this = other;
    1.99 +}
   1.100 +
   1.101 +
   1.102 +// -------------------------------------
   1.103 +// assignment operator
   1.104 +
   1.105 +DigitList&
   1.106 +DigitList::operator=(const DigitList& other)
   1.107 +{
   1.108 +    if (this != &other)
   1.109 +    {
   1.110 +        uprv_memcpy(&fContext, &other.fContext, sizeof(decContext));
   1.111 +
   1.112 +        if (other.fStorage.getCapacity() > fStorage.getCapacity()) {
   1.113 +            fDecNumber = fStorage.resize(other.fStorage.getCapacity());
   1.114 +        }
   1.115 +        // Always reset the fContext.digits, even if fDecNumber was not reallocated,
   1.116 +        // because above we copied fContext from other.fContext.
   1.117 +        fContext.digits = fStorage.getCapacity();
   1.118 +        uprv_decNumberCopy(fDecNumber, other.fDecNumber);
   1.119 +
   1.120 +        {
   1.121 +            // fDouble is lazily created and cached.
   1.122 +            // Avoid potential races with that happening with other.fDouble
   1.123 +            // while we are doing the assignment.
   1.124 +            Mutex mutex;
   1.125 +
   1.126 +            if(other.fHave==kDouble) {
   1.127 +              fUnion.fDouble = other.fUnion.fDouble;
   1.128 +            } else if(other.fHave==kInt64) {
   1.129 +              fUnion.fInt64 = other.fUnion.fInt64;
   1.130 +            }
   1.131 +            fHave = other.fHave;
   1.132 +        }
   1.133 +    }
   1.134 +    return *this;
   1.135 +}
   1.136 +
   1.137 +// -------------------------------------
   1.138 +//    operator ==  (does not exactly match the old DigitList function)
   1.139 +
   1.140 +UBool
   1.141 +DigitList::operator==(const DigitList& that) const
   1.142 +{
   1.143 +    if (this == &that) {
   1.144 +        return TRUE;
   1.145 +    }
   1.146 +    decNumber n;  // Has space for only a none digit value.
   1.147 +    decContext c;
   1.148 +    uprv_decContextDefault(&c, DEC_INIT_BASE);
   1.149 +    c.digits = 1;
   1.150 +    c.traps = 0;
   1.151 +
   1.152 +    uprv_decNumberCompare(&n, this->fDecNumber, that.fDecNumber, &c);
   1.153 +    UBool result = decNumberIsZero(&n);
   1.154 +    return result;
   1.155 +}
   1.156 +
   1.157 +// -------------------------------------
   1.158 +//      comparison function.   Returns 
   1.159 +//         Not Comparable :  -2
   1.160 +//                      < :  -1
   1.161 +//                     == :   0
   1.162 +//                      > :  +1
   1.163 +int32_t DigitList::compare(const DigitList &other) {
   1.164 +    decNumber   result;
   1.165 +    int32_t     savedDigits = fContext.digits;
   1.166 +    fContext.digits = 1;
   1.167 +    uprv_decNumberCompare(&result, this->fDecNumber, other.fDecNumber, &fContext);
   1.168 +    fContext.digits = savedDigits;
   1.169 +    if (decNumberIsZero(&result)) {
   1.170 +        return 0;
   1.171 +    } else if (decNumberIsSpecial(&result)) {
   1.172 +        return -2;
   1.173 +    } else if (result.bits & DECNEG) {
   1.174 +        return -1;
   1.175 +    } else {
   1.176 +        return 1;
   1.177 +    }
   1.178 +}
   1.179 +
   1.180 +
   1.181 +// -------------------------------------
   1.182 +//  Reduce - remove trailing zero digits.
   1.183 +void
   1.184 +DigitList::reduce() {
   1.185 +    uprv_decNumberReduce(fDecNumber, fDecNumber, &fContext);
   1.186 +}
   1.187 +
   1.188 +
   1.189 +// -------------------------------------
   1.190 +//  trim - remove trailing fraction zero digits.
   1.191 +void
   1.192 +DigitList::trim() {
   1.193 +    uprv_decNumberTrim(fDecNumber);
   1.194 +}
   1.195 +
   1.196 +// -------------------------------------
   1.197 +// Resets the digit list; sets all the digits to zero.
   1.198 +
   1.199 +void
   1.200 +DigitList::clear()
   1.201 +{
   1.202 +    uprv_decNumberZero(fDecNumber);
   1.203 +    uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
   1.204 +    internalSetDouble(0.0);
   1.205 +}
   1.206 +
   1.207 +
   1.208 +/**
   1.209 + * Formats a int64_t number into a base 10 string representation, and NULL terminates it.
   1.210 + * @param number The number to format
   1.211 + * @param outputStr The string to output to.  Must be at least MAX_DIGITS+2 in length (21),
   1.212 + *                  to hold the longest int64_t value.
   1.213 + * @return the number of digits written, not including the sign.
   1.214 + */
   1.215 +static int32_t
   1.216 +formatBase10(int64_t number, char *outputStr) {
   1.217 +    // The number is output backwards, starting with the LSD.
   1.218 +    // Fill the buffer from the far end.  After the number is complete,
   1.219 +    // slide the string contents to the front.
   1.220 +
   1.221 +    const int32_t MAX_IDX = MAX_DIGITS+2;
   1.222 +    int32_t destIdx = MAX_IDX;
   1.223 +    outputStr[--destIdx] = 0; 
   1.224 +
   1.225 +    int64_t  n = number;
   1.226 +    if (number < 0) {   // Negative numbers are slightly larger than a postive
   1.227 +        outputStr[--destIdx] = (char)(-(n % 10) + kZero);
   1.228 +        n /= -10;
   1.229 +    }
   1.230 +    do { 
   1.231 +        outputStr[--destIdx] = (char)(n % 10 + kZero);
   1.232 +        n /= 10;
   1.233 +    } while (n > 0);
   1.234 +    
   1.235 +    if (number < 0) {
   1.236 +        outputStr[--destIdx] = '-';
   1.237 +    }
   1.238 +
   1.239 +    // Slide the number to the start of the output str
   1.240 +    U_ASSERT(destIdx >= 0);
   1.241 +    int32_t length = MAX_IDX - destIdx;
   1.242 +    uprv_memmove(outputStr, outputStr+MAX_IDX-length, length);
   1.243 +
   1.244 +    return length;
   1.245 +}
   1.246 +
   1.247 +
   1.248 +// -------------------------------------
   1.249 +//
   1.250 +//  setRoundingMode()
   1.251 +//    For most modes, the meaning and names are the same between the decNumber library
   1.252 +//      (which DigitList follows) and the ICU Formatting Rounding Mode values.
   1.253 +//      The flag constants are different, however.
   1.254 +//
   1.255 +//     Note that ICU's kRoundingUnnecessary is not implemented directly by DigitList.
   1.256 +//     This mode, inherited from Java, means that numbers that would not format exactly
   1.257 +//     will return an error when formatting is attempted.
   1.258 +
   1.259 +void 
   1.260 +DigitList::setRoundingMode(DecimalFormat::ERoundingMode m) {
   1.261 +    enum rounding r;
   1.262 +
   1.263 +    switch (m) {
   1.264 +      case  DecimalFormat::kRoundCeiling:  r = DEC_ROUND_CEILING;   break;
   1.265 +      case  DecimalFormat::kRoundFloor:    r = DEC_ROUND_FLOOR;     break;
   1.266 +      case  DecimalFormat::kRoundDown:     r = DEC_ROUND_DOWN;      break;
   1.267 +      case  DecimalFormat::kRoundUp:       r = DEC_ROUND_UP;        break;
   1.268 +      case  DecimalFormat::kRoundHalfEven: r = DEC_ROUND_HALF_EVEN; break;
   1.269 +      case  DecimalFormat::kRoundHalfDown: r = DEC_ROUND_HALF_DOWN; break;
   1.270 +      case  DecimalFormat::kRoundHalfUp:   r = DEC_ROUND_HALF_UP;   break;
   1.271 +      case  DecimalFormat::kRoundUnnecessary: r = DEC_ROUND_HALF_EVEN; break;
   1.272 +      default:
   1.273 +         // TODO: how to report the problem?
   1.274 +         // Leave existing mode unchanged.
   1.275 +         r = uprv_decContextGetRounding(&fContext);
   1.276 +    }
   1.277 +    uprv_decContextSetRounding(&fContext, r);
   1.278 +  
   1.279 +}
   1.280 +
   1.281 +
   1.282 +// -------------------------------------
   1.283 +
   1.284 +void  
   1.285 +DigitList::setPositive(UBool s) {
   1.286 +    if (s) {
   1.287 +        fDecNumber->bits &= ~DECNEG; 
   1.288 +    } else {
   1.289 +        fDecNumber->bits |= DECNEG;
   1.290 +    }
   1.291 +    internalClear();
   1.292 +}
   1.293 +// -------------------------------------
   1.294 +
   1.295 +void     
   1.296 +DigitList::setDecimalAt(int32_t d) {
   1.297 +    U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0);  // Not Infinity or NaN
   1.298 +    U_ASSERT(d-1>-999999999);
   1.299 +    U_ASSERT(d-1< 999999999);
   1.300 +    int32_t adjustedDigits = fDecNumber->digits;
   1.301 +    if (decNumberIsZero(fDecNumber)) {
   1.302 +        // Account for difference in how zero is represented between DigitList & decNumber.
   1.303 +        adjustedDigits = 0;
   1.304 +    }
   1.305 +    fDecNumber->exponent = d - adjustedDigits;
   1.306 +    internalClear();
   1.307 +}
   1.308 +
   1.309 +int32_t  
   1.310 +DigitList::getDecimalAt() {
   1.311 +    U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0);  // Not Infinity or NaN
   1.312 +    if (decNumberIsZero(fDecNumber) || ((fDecNumber->bits & DECSPECIAL) != 0)) {
   1.313 +        return fDecNumber->exponent;  // Exponent should be zero for these cases.
   1.314 +    }
   1.315 +    return fDecNumber->exponent + fDecNumber->digits;
   1.316 +}
   1.317 +
   1.318 +void     
   1.319 +DigitList::setCount(int32_t c)  {
   1.320 +    U_ASSERT(c <= fContext.digits);
   1.321 +    if (c == 0) {
   1.322 +        // For a value of zero, DigitList sets all fields to zero, while
   1.323 +        // decNumber keeps one digit (with that digit being a zero)
   1.324 +        c = 1;
   1.325 +        fDecNumber->lsu[0] = 0;
   1.326 +    }
   1.327 +    fDecNumber->digits = c;
   1.328 +    internalClear();
   1.329 +}
   1.330 +
   1.331 +int32_t  
   1.332 +DigitList::getCount() const {
   1.333 +    if (decNumberIsZero(fDecNumber) && fDecNumber->exponent==0) {
   1.334 +       // The extra test for exponent==0 is needed because parsing sometimes appends
   1.335 +       // zero digits.  It's bogus, decimalFormatter parsing needs to be cleaned up.
   1.336 +       return 0;
   1.337 +    } else {
   1.338 +       return fDecNumber->digits;
   1.339 +    }
   1.340 +}
   1.341 +    
   1.342 +void     
   1.343 +DigitList::setDigit(int32_t i, char v) {
   1.344 +    int32_t count = fDecNumber->digits;
   1.345 +    U_ASSERT(i<count);
   1.346 +    U_ASSERT(v>='0' && v<='9');
   1.347 +    v &= 0x0f;
   1.348 +    fDecNumber->lsu[count-i-1] = v;
   1.349 +    internalClear();
   1.350 +}
   1.351 +
   1.352 +char     
   1.353 +DigitList::getDigit(int32_t i) {
   1.354 +    int32_t count = fDecNumber->digits;
   1.355 +    U_ASSERT(i<count);
   1.356 +    return fDecNumber->lsu[count-i-1] + '0';
   1.357 +}
   1.358 +
   1.359 +// copied from DigitList::getDigit()
   1.360 +uint8_t
   1.361 +DigitList::getDigitValue(int32_t i) {
   1.362 +    int32_t count = fDecNumber->digits;
   1.363 +    U_ASSERT(i<count);
   1.364 +    return fDecNumber->lsu[count-i-1];
   1.365 +}
   1.366 +
   1.367 +// -------------------------------------
   1.368 +// Appends the digit to the digit list if it's not out of scope.
   1.369 +// Ignores the digit, otherwise.
   1.370 +// 
   1.371 +// This function is horribly inefficient to implement with decNumber because
   1.372 +// the digits are stored least significant first, which requires moving all
   1.373 +// existing digits down one to make space for the new one to be appended.
   1.374 +//
   1.375 +void
   1.376 +DigitList::append(char digit)
   1.377 +{
   1.378 +    U_ASSERT(digit>='0' && digit<='9');
   1.379 +    // Ignore digits which exceed the precision we can represent
   1.380 +    //    And don't fix for larger precision.  Fix callers instead.
   1.381 +    if (decNumberIsZero(fDecNumber)) {
   1.382 +        // Zero needs to be special cased because of the difference in the way
   1.383 +        // that the old DigitList and decNumber represent it.
   1.384 +        // digit cout was zero for digitList, is one for decNumber
   1.385 +        fDecNumber->lsu[0] = digit & 0x0f;
   1.386 +        fDecNumber->digits = 1;
   1.387 +        fDecNumber->exponent--;     // To match the old digit list implementation.
   1.388 +    } else {
   1.389 +        int32_t nDigits = fDecNumber->digits;
   1.390 +        if (nDigits < fContext.digits) {
   1.391 +            int i;
   1.392 +            for (i=nDigits; i>0; i--) {
   1.393 +                fDecNumber->lsu[i] = fDecNumber->lsu[i-1];
   1.394 +            }
   1.395 +            fDecNumber->lsu[0] = digit & 0x0f;
   1.396 +            fDecNumber->digits++;
   1.397 +            // DigitList emulation - appending doesn't change the magnitude of existing
   1.398 +            //                       digits.  With decNumber's decimal being after the
   1.399 +            //                       least signficant digit, we need to adjust the exponent.
   1.400 +            fDecNumber->exponent--;
   1.401 +        }
   1.402 +    }
   1.403 +    internalClear();
   1.404 +}
   1.405 +
   1.406 +// -------------------------------------
   1.407 +
   1.408 +/**
   1.409 + * Currently, getDouble() depends on strtod() to do its conversion.
   1.410 + *
   1.411 + * WARNING!!
   1.412 + * This is an extremely costly function. ~1/2 of the conversion time
   1.413 + * can be linked to this function.
   1.414 + */
   1.415 +double
   1.416 +DigitList::getDouble() const
   1.417 +{
   1.418 +    static char gDecimal = 0;
   1.419 +    char decimalSeparator;
   1.420 +    {
   1.421 +        Mutex mutex;
   1.422 +        if (fHave == kDouble) {
   1.423 +            return fUnion.fDouble;
   1.424 +        } else if(fHave == kInt64) {
   1.425 +            return (double)fUnion.fInt64;
   1.426 +        }
   1.427 +        decimalSeparator = gDecimal;
   1.428 +    }
   1.429 +
   1.430 +    if (decimalSeparator == 0) {
   1.431 +        // We need to know the decimal separator character that will be used with strtod().
   1.432 +        // Depends on the C runtime global locale.
   1.433 +        // Most commonly is '.'
   1.434 +        // TODO: caching could fail if the global locale is changed on the fly.
   1.435 +        char rep[MAX_DIGITS];
   1.436 +        sprintf(rep, "%+1.1f", 1.0);
   1.437 +        decimalSeparator = rep[2];
   1.438 +    }
   1.439 +
   1.440 +    double tDouble = 0.0;
   1.441 +    if (isZero()) {
   1.442 +        tDouble = 0.0;
   1.443 +        if (decNumberIsNegative(fDecNumber)) {
   1.444 +            tDouble /= -1;
   1.445 +        }
   1.446 +    } else if (isInfinite()) {
   1.447 +        if (std::numeric_limits<double>::has_infinity) {
   1.448 +            tDouble = std::numeric_limits<double>::infinity();
   1.449 +        } else {
   1.450 +            tDouble = std::numeric_limits<double>::max();
   1.451 +        }
   1.452 +        if (!isPositive()) {
   1.453 +            tDouble = -tDouble; //this was incorrectly "-fDouble" originally.
   1.454 +        } 
   1.455 +    } else {
   1.456 +        MaybeStackArray<char, MAX_DBL_DIGITS+18> s;
   1.457 +           // Note:  14 is a  magic constant from the decNumber library documentation,
   1.458 +           //        the max number of extra characters beyond the number of digits 
   1.459 +           //        needed to represent the number in string form.  Add a few more
   1.460 +           //        for the additional digits we retain.
   1.461 +
   1.462 +        // Round down to appx. double precision, if the number is longer than that.
   1.463 +        // Copy the number first, so that we don't modify the original.
   1.464 +        if (getCount() > MAX_DBL_DIGITS + 3) {
   1.465 +            DigitList numToConvert(*this);
   1.466 +            numToConvert.reduce();    // Removes any trailing zeros, so that digit count is good.
   1.467 +            numToConvert.round(MAX_DBL_DIGITS+3);
   1.468 +            uprv_decNumberToString(numToConvert.fDecNumber, s.getAlias());
   1.469 +            // TODO:  how many extra digits should be included for an accurate conversion?
   1.470 +        } else {
   1.471 +            uprv_decNumberToString(this->fDecNumber, s.getAlias());
   1.472 +        }
   1.473 +        U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18);
   1.474 +        
   1.475 +        if (decimalSeparator != '.') {
   1.476 +            char *decimalPt = strchr(s.getAlias(), '.');
   1.477 +            if (decimalPt != NULL) {
   1.478 +                *decimalPt = decimalSeparator;
   1.479 +            }
   1.480 +        }
   1.481 +        char *end = NULL;
   1.482 +        tDouble = uprv_strtod(s.getAlias(), &end);
   1.483 +    }
   1.484 +    {
   1.485 +        Mutex mutex;
   1.486 +        DigitList *nonConstThis = const_cast<DigitList *>(this);
   1.487 +        nonConstThis->internalSetDouble(tDouble);
   1.488 +        gDecimal = decimalSeparator;
   1.489 +    }
   1.490 +    return tDouble;
   1.491 +}
   1.492 +
   1.493 +// -------------------------------------
   1.494 +
   1.495 +/**
   1.496 + *  convert this number to an int32_t.   Round if there is a fractional part.
   1.497 + *  Return zero if the number cannot be represented.
   1.498 + */
   1.499 +int32_t DigitList::getLong() /*const*/
   1.500 +{
   1.501 +    int32_t result = 0;
   1.502 +    if (fDecNumber->digits + fDecNumber->exponent > 10) {
   1.503 +        // Overflow, absolute value too big.
   1.504 +        return result;
   1.505 +    }
   1.506 +    if (fDecNumber->exponent != 0) {
   1.507 +        // Force to an integer, with zero exponent, rounding if necessary.
   1.508 +        //   (decNumberToInt32 will only work if the exponent is exactly zero.)
   1.509 +        DigitList copy(*this);
   1.510 +        DigitList zero;
   1.511 +        uprv_decNumberQuantize(copy.fDecNumber, copy.fDecNumber, zero.fDecNumber, &fContext);
   1.512 +        result = uprv_decNumberToInt32(copy.fDecNumber, &fContext);
   1.513 +    } else {
   1.514 +        result = uprv_decNumberToInt32(fDecNumber, &fContext);
   1.515 +    }
   1.516 +    return result;
   1.517 +}
   1.518 +
   1.519 +
   1.520 +/**
   1.521 + *  convert this number to an int64_t.   Truncate if there is a fractional part.
   1.522 + *  Return zero if the number cannot be represented.
   1.523 + */
   1.524 +int64_t DigitList::getInt64() /*const*/ {
   1.525 +    if(fHave==kInt64) {
   1.526 +      return fUnion.fInt64;
   1.527 +    } 
   1.528 +    // Truncate if non-integer.
   1.529 +    // Return 0 if out of range.
   1.530 +    // Range of in64_t is -9223372036854775808 to 9223372036854775807  (19 digits)
   1.531 +    //
   1.532 +    if (fDecNumber->digits + fDecNumber->exponent > 19) {
   1.533 +        // Overflow, absolute value too big.
   1.534 +        return 0;
   1.535 +    }
   1.536 +
   1.537 +    // The number of integer digits may differ from the number of digits stored
   1.538 +    //   in the decimal number.
   1.539 +    //     for 12.345  numIntDigits = 2, number->digits = 5
   1.540 +    //     for 12E4    numIntDigits = 6, number->digits = 2
   1.541 +    // The conversion ignores the fraction digits in the first case,
   1.542 +    // and fakes up extra zero digits in the second.
   1.543 +    // TODO:  It would be faster to store a table of powers of ten to multiply by
   1.544 +    //        instead of looping over zero digits, multiplying each time.
   1.545 +
   1.546 +    int32_t numIntDigits = fDecNumber->digits + fDecNumber->exponent;
   1.547 +    uint64_t value = 0;
   1.548 +    for (int32_t i = 0; i < numIntDigits; i++) {
   1.549 +        // Loop is iterating over digits starting with the most significant.
   1.550 +        // Numbers are stored with the least significant digit at index zero.
   1.551 +        int32_t digitIndex = fDecNumber->digits - i - 1;
   1.552 +        int32_t v = (digitIndex >= 0) ? fDecNumber->lsu[digitIndex] : 0;
   1.553 +        value = value * (uint64_t)10 + (uint64_t)v;
   1.554 +    }
   1.555 +
   1.556 +    if (decNumberIsNegative(fDecNumber)) {
   1.557 +        value = ~value;
   1.558 +        value += 1;
   1.559 +    }
   1.560 +    int64_t svalue = (int64_t)value;
   1.561 +
   1.562 +    // Check overflow.  It's convenient that the MSD is 9 only on overflow, the amount of
   1.563 +    //                  overflow can't wrap too far.  The test will also fail -0, but
   1.564 +    //                  that does no harm; the right answer is 0.
   1.565 +    if (numIntDigits == 19) {
   1.566 +        if (( decNumberIsNegative(fDecNumber) && svalue>0) ||
   1.567 +            (!decNumberIsNegative(fDecNumber) && svalue<0)) {
   1.568 +            svalue = 0;
   1.569 +        }
   1.570 +    }
   1.571 +        
   1.572 +    return svalue;
   1.573 +}
   1.574 +
   1.575 +
   1.576 +/**
   1.577 + *  Return a string form of this number.
   1.578 + *     Format is as defined by the decNumber library, for interchange of
   1.579 + *     decimal numbers.
   1.580 + */
   1.581 +void DigitList::getDecimal(CharString &str, UErrorCode &status) {
   1.582 +    if (U_FAILURE(status)) {
   1.583 +        return;
   1.584 +    }
   1.585 +
   1.586 +    // A decimal number in string form can, worst case, be 14 characters longer
   1.587 +    //  than the number of digits.  So says the decNumber library doc.
   1.588 +    int32_t maxLength = fDecNumber->digits + 14;
   1.589 +    int32_t capacity = 0;
   1.590 +    char *buffer = str.clear().getAppendBuffer(maxLength, 0, capacity, status);
   1.591 +    if (U_FAILURE(status)) {
   1.592 +        return;    // Memory allocation error on growing the string.
   1.593 +    }
   1.594 +    U_ASSERT(capacity >= maxLength);
   1.595 +    uprv_decNumberToString(this->fDecNumber, buffer);
   1.596 +    U_ASSERT((int32_t)uprv_strlen(buffer) <= maxLength);
   1.597 +    str.append(buffer, -1, status);
   1.598 +}
   1.599 +
   1.600 +/**
   1.601 + * Return true if this is an integer value that can be held
   1.602 + * by an int32_t type.
   1.603 + */
   1.604 +UBool
   1.605 +DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/
   1.606 +{
   1.607 +    if (decNumberIsSpecial(this->fDecNumber)) {
   1.608 +        // NaN or Infinity.  Does not fit in int32.
   1.609 +        return FALSE;
   1.610 +    }
   1.611 +    uprv_decNumberTrim(this->fDecNumber);
   1.612 +    if (fDecNumber->exponent < 0) {
   1.613 +        // Number contains fraction digits.
   1.614 +        return FALSE;
   1.615 +    }
   1.616 +    if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
   1.617 +        (fDecNumber->bits & DECNEG) != 0) {
   1.618 +        // Negative Zero, not ingored.  Cannot represent as a long.
   1.619 +        return FALSE;
   1.620 +    }
   1.621 +    if (fDecNumber->digits + fDecNumber->exponent < 10) {
   1.622 +        // The number is 9 or fewer digits.
   1.623 +        // The max and min int32 are 10 digts, so this number fits.
   1.624 +        // This is the common case.
   1.625 +        return TRUE;
   1.626 +    }
   1.627 +
   1.628 +    // TODO:  Should cache these constants; construction is relatively costly.
   1.629 +    //        But not of huge consequence; they're only needed for 10 digit ints.
   1.630 +    UErrorCode status = U_ZERO_ERROR;
   1.631 +    DigitList min32; min32.set("-2147483648", status);
   1.632 +    if (this->compare(min32) < 0) {
   1.633 +        return FALSE;
   1.634 +    }
   1.635 +    DigitList max32; max32.set("2147483647", status);
   1.636 +    if (this->compare(max32) > 0) {
   1.637 +        return FALSE;
   1.638 +    }
   1.639 +    if (U_FAILURE(status)) {
   1.640 +        return FALSE;
   1.641 +    }
   1.642 +    return true;
   1.643 +}
   1.644 +
   1.645 +
   1.646 +
   1.647 +/**
   1.648 + * Return true if the number represented by this object can fit into
   1.649 + * a long.
   1.650 + */
   1.651 +UBool
   1.652 +DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/
   1.653 +{
   1.654 +    if (decNumberIsSpecial(this->fDecNumber)) {
   1.655 +        // NaN or Infinity.  Does not fit in int32.
   1.656 +        return FALSE;
   1.657 +    }
   1.658 +    uprv_decNumberTrim(this->fDecNumber);
   1.659 +    if (fDecNumber->exponent < 0) {
   1.660 +        // Number contains fraction digits.
   1.661 +        return FALSE;
   1.662 +    }
   1.663 +    if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
   1.664 +        (fDecNumber->bits & DECNEG) != 0) {
   1.665 +        // Negative Zero, not ingored.  Cannot represent as a long.
   1.666 +        return FALSE;
   1.667 +    }
   1.668 +    if (fDecNumber->digits + fDecNumber->exponent < 19) {
   1.669 +        // The number is 18 or fewer digits.
   1.670 +        // The max and min int64 are 19 digts, so this number fits.
   1.671 +        // This is the common case.
   1.672 +        return TRUE;
   1.673 +    }
   1.674 +
   1.675 +    // TODO:  Should cache these constants; construction is relatively costly.
   1.676 +    //        But not of huge consequence; they're only needed for 19 digit ints.
   1.677 +    UErrorCode status = U_ZERO_ERROR;
   1.678 +    DigitList min64; min64.set("-9223372036854775808", status);
   1.679 +    if (this->compare(min64) < 0) {
   1.680 +        return FALSE;
   1.681 +    }
   1.682 +    DigitList max64; max64.set("9223372036854775807", status);
   1.683 +    if (this->compare(max64) > 0) {
   1.684 +        return FALSE;
   1.685 +    }
   1.686 +    if (U_FAILURE(status)) {
   1.687 +        return FALSE;
   1.688 +    }
   1.689 +    return true;
   1.690 +}
   1.691 +
   1.692 +
   1.693 +// -------------------------------------
   1.694 +
   1.695 +void
   1.696 +DigitList::set(int32_t source)
   1.697 +{
   1.698 +    set((int64_t)source);
   1.699 +    internalSetDouble(source);
   1.700 +}
   1.701 +
   1.702 +// -------------------------------------
   1.703 +/**
   1.704 + * Set an int64, via decnumber
   1.705 + */
   1.706 +void
   1.707 +DigitList::set(int64_t source)
   1.708 +{
   1.709 +    char str[MAX_DIGITS+2];   // Leave room for sign and trailing nul.
   1.710 +    formatBase10(source, str);
   1.711 +    U_ASSERT(uprv_strlen(str) < sizeof(str));
   1.712 +
   1.713 +    uprv_decNumberFromString(fDecNumber, str, &fContext);
   1.714 +    internalSetDouble(source);
   1.715 +}
   1.716 +
   1.717 +/**
   1.718 + * Set an int64, with no decnumber
   1.719 + */
   1.720 +void
   1.721 +DigitList::setInteger(int64_t source)
   1.722 +{
   1.723 +  fDecNumber=NULL;
   1.724 +  internalSetInt64(source);
   1.725 +}
   1.726 +
   1.727 +
   1.728 +// -------------------------------------
   1.729 +/**
   1.730 + * Set the DigitList from a decimal number string.
   1.731 + *
   1.732 + * The incoming string _must_ be nul terminated, even though it is arriving
   1.733 + * as a StringPiece because that is what the decNumber library wants.
   1.734 + * We can get away with this for an internal function; it would not
   1.735 + * be acceptable for a public API.
   1.736 + */
   1.737 +void
   1.738 +DigitList::set(const StringPiece &source, UErrorCode &status, uint32_t /*fastpathBits*/) {
   1.739 +    if (U_FAILURE(status)) {
   1.740 +        return;
   1.741 +    }
   1.742 +
   1.743 +#if 0    
   1.744 +    if(fastpathBits==(kFastpathOk|kNoDecimal)) {
   1.745 +      int32_t size = source.size();
   1.746 +      const char *data = source.data();
   1.747 +      int64_t r = 0;
   1.748 +      int64_t m = 1;
   1.749 +      // fast parse
   1.750 +      while(size>0) {
   1.751 +        char ch = data[--size];
   1.752 +        if(ch=='+') {
   1.753 +          break;
   1.754 +        } else if(ch=='-') {
   1.755 +          r = -r;
   1.756 +          break;
   1.757 +        } else {
   1.758 +          int64_t d = ch-'0';
   1.759 +          //printf("CH[%d]=%c, %d, *=%d\n", size,ch, (int)d, (int)m);
   1.760 +          r+=(d)*m;
   1.761 +          m *= 10;
   1.762 +        }
   1.763 +      }
   1.764 +      //printf("R=%d\n", r);
   1.765 +      set(r);
   1.766 +    } else
   1.767 +#endif
   1.768 +        {
   1.769 +      // Figure out a max number of digits to use during the conversion, and
   1.770 +      // resize the number up if necessary.
   1.771 +      int32_t numDigits = source.length();
   1.772 +      if (numDigits > fContext.digits) {
   1.773 +        // fContext.digits == fStorage.getCapacity()
   1.774 +        decNumber *t = fStorage.resize(numDigits, fStorage.getCapacity());
   1.775 +        if (t == NULL) {
   1.776 +          status = U_MEMORY_ALLOCATION_ERROR;
   1.777 +          return;
   1.778 +        }
   1.779 +        fDecNumber = t;
   1.780 +        fContext.digits = numDigits;
   1.781 +      }
   1.782 +
   1.783 +      fContext.status = 0;
   1.784 +      uprv_decNumberFromString(fDecNumber, source.data(), &fContext);
   1.785 +      if ((fContext.status & DEC_Conversion_syntax) != 0) {
   1.786 +        status = U_DECIMAL_NUMBER_SYNTAX_ERROR;
   1.787 +      }
   1.788 +    }
   1.789 +    internalClear();
   1.790 +}   
   1.791 +
   1.792 +/**
   1.793 + * Set the digit list to a representation of the given double value.
   1.794 + * This method supports both fixed-point and exponential notation.
   1.795 + * @param source Value to be converted.
   1.796 + */
   1.797 +void
   1.798 +DigitList::set(double source)
   1.799 +{
   1.800 +    // for now, simple implementation; later, do proper IEEE stuff
   1.801 +    char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough)
   1.802 +
   1.803 +    // Generate a representation of the form /[+-][0-9].[0-9]+e[+-][0-9]+/
   1.804 +    // Can also generate /[+-]nan/ or /[+-]inf/
   1.805 +    // TODO: Use something other than sprintf() here, since it's behavior is somewhat platform specific.
   1.806 +    //       That is why infinity is special cased here.
   1.807 +    if (uprv_isInfinite(source)) {
   1.808 +        if (uprv_isNegativeInfinity(source)) {
   1.809 +            uprv_strcpy(rep,"-inf"); // Handle negative infinity
   1.810 +        } else {
   1.811 +            uprv_strcpy(rep,"inf");
   1.812 +        }
   1.813 +    } else {
   1.814 +        sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source);
   1.815 +    }
   1.816 +    U_ASSERT(uprv_strlen(rep) < sizeof(rep));
   1.817 +
   1.818 +    // uprv_decNumberFromString() will parse the string expecting '.' as a
   1.819 +    // decimal separator, however sprintf() can use ',' in certain locales.
   1.820 +    // Overwrite a ',' with '.' here before proceeding.
   1.821 +    char *decimalSeparator = strchr(rep, ',');
   1.822 +    if (decimalSeparator != NULL) {
   1.823 +        *decimalSeparator = '.';
   1.824 +    }
   1.825 +
   1.826 +    // Create a decNumber from the string.
   1.827 +    uprv_decNumberFromString(fDecNumber, rep, &fContext);
   1.828 +    uprv_decNumberTrim(fDecNumber);
   1.829 +    internalSetDouble(source);
   1.830 +}
   1.831 +
   1.832 +// -------------------------------------
   1.833 +
   1.834 +/*
   1.835 + * Multiply
   1.836 + *      The number will be expanded if need be to retain full precision.
   1.837 + *      In practice, for formatting, multiply is by 10, 100 or 1000, so more digits
   1.838 + *      will not be required for this use.
   1.839 + */
   1.840 +void
   1.841 +DigitList::mult(const DigitList &other, UErrorCode &status) {
   1.842 +    fContext.status = 0;
   1.843 +    int32_t requiredDigits = this->digits() + other.digits();
   1.844 +    if (requiredDigits > fContext.digits) {
   1.845 +        reduce();    // Remove any trailing zeros
   1.846 +        int32_t requiredDigits = this->digits() + other.digits();
   1.847 +        ensureCapacity(requiredDigits, status);
   1.848 +    }
   1.849 +    uprv_decNumberMultiply(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
   1.850 +    internalClear();
   1.851 +}
   1.852 +
   1.853 +// -------------------------------------
   1.854 +
   1.855 +/*
   1.856 + * Divide
   1.857 + *      The number will _not_ be expanded for inexact results.
   1.858 + *      TODO:  probably should expand some, for rounding increments that
   1.859 + *             could add a few digits, e.g. .25, but not expand arbitrarily.
   1.860 + */
   1.861 +void
   1.862 +DigitList::div(const DigitList &other, UErrorCode &status) {
   1.863 +    if (U_FAILURE(status)) {
   1.864 +        return;
   1.865 +    }
   1.866 +    uprv_decNumberDivide(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
   1.867 +    internalClear();
   1.868 +}
   1.869 +
   1.870 +// -------------------------------------
   1.871 +
   1.872 +/*
   1.873 + * ensureCapacity.   Grow the digit storage for the number if it's less than the requested
   1.874 + *         amount.  Never reduce it.  Available size is kept in fContext.digits.
   1.875 + */
   1.876 +void
   1.877 +DigitList::ensureCapacity(int32_t requestedCapacity, UErrorCode &status) {
   1.878 +    if (U_FAILURE(status)) {
   1.879 +        return;
   1.880 +    }
   1.881 +    if (requestedCapacity <= 0) {
   1.882 +        status = U_ILLEGAL_ARGUMENT_ERROR;
   1.883 +        return;
   1.884 +    }
   1.885 +    if (requestedCapacity > DEC_MAX_DIGITS) {
   1.886 +        // Don't report an error for requesting too much.
   1.887 +        // Arithemetic Results will be rounded to what can be supported.
   1.888 +        //   At 999,999,999 max digits, exceeding the limit is not too likely!
   1.889 +        requestedCapacity = DEC_MAX_DIGITS;
   1.890 +    }
   1.891 +    if (requestedCapacity > fContext.digits) {
   1.892 +        decNumber *newBuffer = fStorage.resize(requestedCapacity, fStorage.getCapacity());
   1.893 +        if (newBuffer == NULL) {
   1.894 +            status = U_MEMORY_ALLOCATION_ERROR;
   1.895 +            return;
   1.896 +        }
   1.897 +        fContext.digits = requestedCapacity;
   1.898 +        fDecNumber = newBuffer;
   1.899 +    }
   1.900 +}
   1.901 +
   1.902 +// -------------------------------------
   1.903 +
   1.904 +/**
   1.905 + * Round the representation to the given number of digits.
   1.906 + * @param maximumDigits The maximum number of digits to be shown.
   1.907 + * Upon return, count will be less than or equal to maximumDigits.
   1.908 + */
   1.909 +void
   1.910 +DigitList::round(int32_t maximumDigits)
   1.911 +{
   1.912 +    int32_t savedDigits  = fContext.digits;
   1.913 +    fContext.digits = maximumDigits;
   1.914 +    uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext);
   1.915 +    fContext.digits = savedDigits;
   1.916 +    uprv_decNumberTrim(fDecNumber);
   1.917 +    internalClear();
   1.918 +}
   1.919 +
   1.920 +
   1.921 +void
   1.922 +DigitList::roundFixedPoint(int32_t maximumFractionDigits) {
   1.923 +    trim();        // Remove trailing zeros.
   1.924 +    if (fDecNumber->exponent >= -maximumFractionDigits) {
   1.925 +        return;
   1.926 +    }
   1.927 +    decNumber scale;   // Dummy decimal number, but with the desired number of
   1.928 +    uprv_decNumberZero(&scale);    //    fraction digits.
   1.929 +    scale.exponent = -maximumFractionDigits;
   1.930 +    scale.lsu[0] = 1;
   1.931 +    
   1.932 +    uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext);
   1.933 +    trim();
   1.934 +    internalClear();
   1.935 +}
   1.936 +
   1.937 +// -------------------------------------
   1.938 +
   1.939 +void
   1.940 +DigitList::toIntegralValue() {
   1.941 +    uprv_decNumberToIntegralValue(fDecNumber, fDecNumber, &fContext);
   1.942 +}
   1.943 +
   1.944 +
   1.945 +// -------------------------------------
   1.946 +UBool
   1.947 +DigitList::isZero() const
   1.948 +{
   1.949 +    return decNumberIsZero(fDecNumber);
   1.950 +}
   1.951 +
   1.952 +U_NAMESPACE_END
   1.953 +#endif // #if !UCONFIG_NO_FORMATTING
   1.954 +
   1.955 +//eof

mercurial