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