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