1 // 2017 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 4 #include "unicode/utypes.h" 5 6 #if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT 7 8 #include "uassert.h" 9 #include <cmath> 10 #include "cmemory.h" 11 #include "decNumber.h" 12 #include <limits> 13 #include "number_decimalquantity.h" 14 #include "decContext.h" 15 #include "decNumber.h" 16 #include "number_roundingutils.h" 17 #include "unicode/plurrule.h" 18 19 using namespace icu; 20 using namespace icu::number; 21 using namespace icu::number::impl; 22 23 namespace { 24 25 int8_t NEGATIVE_FLAG = 1; 26 int8_t INFINITY_FLAG = 2; 27 int8_t NAN_FLAG = 4; 28 29 static constexpr int32_t DEFAULT_DIGITS = 34; 30 typedef MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS> DecNumberWithStorage; 31 32 /** Helper function to convert a decNumber-compatible string into a decNumber. */ 33 void stringToDecNumber(StringPiece n, DecNumberWithStorage &dn) { 34 decContext set; 35 uprv_decContextDefault(&set, DEC_INIT_BASE); 36 uprv_decContextSetRounding(&set, DEC_ROUND_HALF_EVEN); 37 set.traps = 0; // no traps, thank you 38 if (n.length() > DEFAULT_DIGITS) { 39 dn.resize(n.length(), 0); 40 set.digits = n.length(); 41 } else { 42 set.digits = DEFAULT_DIGITS; 43 } 44 uprv_decNumberFromString(dn.getAlias(), n.data(), &set); 45 U_ASSERT(DECDPUN == 1); 46 } 47 48 /** Helper function for safe subtraction (no overflow). */ 49 inline int32_t safeSubtract(int32_t a, int32_t b) { 50 // Note: In C++, signed integer subtraction is undefined behavior. 51 int32_t diff = static_cast<int32_t>(static_cast<uint32_t>(a) - static_cast<uint32_t>(b)); 52 if (b < 0 && diff < a) { return INT32_MAX; } 53 if (b > 0 && diff > a) { return INT32_MIN; } 54 return diff; 55 } 56 57 static double DOUBLE_MULTIPLIERS[] = { 58 1e0, 59 1e1, 60 1e2, 61 1e3, 62 1e4, 63 1e5, 64 1e6, 65 1e7, 66 1e8, 67 1e9, 68 1e10, 69 1e11, 70 1e12, 71 1e13, 72 1e14, 73 1e15, 74 1e16, 75 1e17, 76 1e18, 77 1e19, 78 1e20, 79 1e21}; 80 81 } // namespace 82 83 84 DecimalQuantity::DecimalQuantity() { 85 setBcdToZero(); 86 flags = 0; 87 } 88 89 DecimalQuantity::~DecimalQuantity() { 90 if (usingBytes) { 91 uprv_free(fBCD.bcdBytes.ptr); 92 fBCD.bcdBytes.ptr = nullptr; 93 usingBytes = false; 94 } 95 } 96 97 DecimalQuantity::DecimalQuantity(const DecimalQuantity &other) { 98 *this = other; 99 } 100 101 DecimalQuantity &DecimalQuantity::operator=(const DecimalQuantity &other) { 102 if (this == &other) { 103 return *this; 104 } 105 copyBcdFrom(other); 106 lOptPos = other.lOptPos; 107 lReqPos = other.lReqPos; 108 rReqPos = other.rReqPos; 109 rOptPos = other.rOptPos; 110 scale = other.scale; 111 precision = other.precision; 112 flags = other.flags; 113 origDouble = other.origDouble; 114 origDelta = other.origDelta; 115 isApproximate = other.isApproximate; 116 return *this; 117 } 118 119 void DecimalQuantity::clear() { 120 lOptPos = INT32_MAX; 121 lReqPos = 0; 122 rReqPos = 0; 123 rOptPos = INT32_MIN; 124 flags = 0; 125 setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data 126 } 127 128 void DecimalQuantity::setIntegerLength(int32_t minInt, int32_t maxInt) { 129 // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class. 130 U_ASSERT(minInt >= 0); 131 U_ASSERT(maxInt >= minInt); 132 133 // Save values into internal state 134 // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE 135 lOptPos = maxInt; 136 lReqPos = minInt; 137 } 138 139 void DecimalQuantity::setFractionLength(int32_t minFrac, int32_t maxFrac) { 140 // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class. 141 U_ASSERT(minFrac >= 0); 142 U_ASSERT(maxFrac >= minFrac); 143 144 // Save values into internal state 145 // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE 146 rReqPos = -minFrac; 147 rOptPos = -maxFrac; 148 } 149 150 uint64_t DecimalQuantity::getPositionFingerprint() const { 151 uint64_t fingerprint = 0; 152 fingerprint ^= lOptPos; 153 fingerprint ^= (lReqPos << 16); 154 fingerprint ^= (static_cast<uint64_t>(rReqPos) << 32); 155 fingerprint ^= (static_cast<uint64_t>(rOptPos) << 48); 156 return fingerprint; 157 } 158 159 void DecimalQuantity::roundToIncrement(double roundingIncrement, RoundingMode roundingMode, 160 int32_t minMaxFrac, UErrorCode& status) { 161 // TODO: This is innefficient. Improve? 162 // TODO: Should we convert to decNumber instead? 163 double temp = toDouble(); 164 temp /= roundingIncrement; 165 setToDouble(temp); 166 roundToMagnitude(0, roundingMode, status); 167 temp = toDouble(); 168 temp *= roundingIncrement; 169 setToDouble(temp); 170 // Since we reset the value to a double, we need to specify the rounding boundary 171 // in order to get the DecimalQuantity out of approximation mode. 172 roundToMagnitude(-minMaxFrac, roundingMode, status); 173 } 174 175 void DecimalQuantity::multiplyBy(int32_t multiplicand) { 176 if (isInfinite() || isZero() || isNaN()) { 177 return; 178 } 179 // TODO: Should we convert to decNumber instead? 180 double temp = toDouble(); 181 temp *= multiplicand; 182 setToDouble(temp); 183 } 184 185 int32_t DecimalQuantity::getMagnitude() const { 186 U_ASSERT(precision != 0); 187 return scale + precision - 1; 188 } 189 190 void DecimalQuantity::adjustMagnitude(int32_t delta) { 191 if (precision != 0) { 192 scale += delta; 193 origDelta += delta; 194 } 195 } 196 197 StandardPlural::Form DecimalQuantity::getStandardPlural(const PluralRules *rules) const { 198 if (rules == nullptr) { 199 // Fail gracefully if the user didn't provide a PluralRules 200 return StandardPlural::Form::OTHER; 201 } else { 202 UnicodeString ruleString = rules->select(*this); 203 return StandardPlural::orOtherFromString(ruleString); 204 } 205 } 206 207 double DecimalQuantity::getPluralOperand(PluralOperand operand) const { 208 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 209 // See the comment at the top of this file explaining the "isApproximate" field. 210 U_ASSERT(!isApproximate); 211 212 switch (operand) { 213 case PLURAL_OPERAND_I: 214 return static_cast<double>(toLong()); 215 case PLURAL_OPERAND_F: 216 return static_cast<double>(toFractionLong(true)); 217 case PLURAL_OPERAND_T: 218 return static_cast<double>(toFractionLong(false)); 219 case PLURAL_OPERAND_V: 220 return fractionCount(); 221 case PLURAL_OPERAND_W: 222 return fractionCountWithoutTrailingZeros(); 223 default: 224 return std::abs(toDouble()); 225 } 226 } 227 228 int32_t DecimalQuantity::getUpperDisplayMagnitude() const { 229 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 230 // See the comment in the header file explaining the "isApproximate" field. 231 U_ASSERT(!isApproximate); 232 233 int32_t magnitude = scale + precision; 234 int32_t result = (lReqPos > magnitude) ? lReqPos : (lOptPos < magnitude) ? lOptPos : magnitude; 235 return result - 1; 236 } 237 238 int32_t DecimalQuantity::getLowerDisplayMagnitude() const { 239 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 240 // See the comment in the header file explaining the "isApproximate" field. 241 U_ASSERT(!isApproximate); 242 243 int32_t magnitude = scale; 244 int32_t result = (rReqPos < magnitude) ? rReqPos : (rOptPos > magnitude) ? rOptPos : magnitude; 245 return result; 246 } 247 248 int8_t DecimalQuantity::getDigit(int32_t magnitude) const { 249 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 250 // See the comment at the top of this file explaining the "isApproximate" field. 251 U_ASSERT(!isApproximate); 252 253 return getDigitPos(magnitude - scale); 254 } 255 256 int32_t DecimalQuantity::fractionCount() const { 257 return -getLowerDisplayMagnitude(); 258 } 259 260 int32_t DecimalQuantity::fractionCountWithoutTrailingZeros() const { 261 return -scale > 0 ? -scale : 0; // max(-scale, 0) 262 } 263 264 bool DecimalQuantity::isNegative() const { 265 return (flags & NEGATIVE_FLAG) != 0; 266 } 267 268 bool DecimalQuantity::isInfinite() const { 269 return (flags & INFINITY_FLAG) != 0; 270 } 271 272 bool DecimalQuantity::isNaN() const { 273 return (flags & NAN_FLAG) != 0; 274 } 275 276 bool DecimalQuantity::isZero() const { 277 return precision == 0; 278 } 279 280 DecimalQuantity &DecimalQuantity::setToInt(int32_t n) { 281 setBcdToZero(); 282 flags = 0; 283 if (n < 0) { 284 flags |= NEGATIVE_FLAG; 285 n = -n; 286 } 287 if (n != 0) { 288 _setToInt(n); 289 compact(); 290 } 291 return *this; 292 } 293 294 void DecimalQuantity::_setToInt(int32_t n) { 295 if (n == INT32_MIN) { 296 readLongToBcd(-static_cast<int64_t>(n)); 297 } else { 298 readIntToBcd(n); 299 } 300 } 301 302 DecimalQuantity &DecimalQuantity::setToLong(int64_t n) { 303 setBcdToZero(); 304 flags = 0; 305 if (n < 0) { 306 flags |= NEGATIVE_FLAG; 307 n = -n; 308 } 309 if (n != 0) { 310 _setToLong(n); 311 compact(); 312 } 313 return *this; 314 } 315 316 void DecimalQuantity::_setToLong(int64_t n) { 317 if (n == INT64_MIN) { 318 static const char *int64minStr = "9.223372036854775808E+18"; 319 DecNumberWithStorage dn; 320 stringToDecNumber(int64minStr, dn); 321 readDecNumberToBcd(dn.getAlias()); 322 } else if (n <= INT32_MAX) { 323 readIntToBcd(static_cast<int32_t>(n)); 324 } else { 325 readLongToBcd(n); 326 } 327 } 328 329 DecimalQuantity &DecimalQuantity::setToDouble(double n) { 330 setBcdToZero(); 331 flags = 0; 332 // signbit() from <math.h> handles +0.0 vs -0.0 333 if (std::signbit(n) != 0) { 334 flags |= NEGATIVE_FLAG; 335 n = -n; 336 } 337 if (std::isnan(n) != 0) { 338 flags |= NAN_FLAG; 339 } else if (std::isfinite(n) == 0) { 340 flags |= INFINITY_FLAG; 341 } else if (n != 0) { 342 _setToDoubleFast(n); 343 compact(); 344 } 345 return *this; 346 } 347 348 void DecimalQuantity::_setToDoubleFast(double n) { 349 isApproximate = true; 350 origDouble = n; 351 origDelta = 0; 352 353 // Make sure the double is an IEEE 754 double. If not, fall back to the slow path right now. 354 // TODO: Make a fast path for other types of doubles. 355 if (!std::numeric_limits<double>::is_iec559) { 356 convertToAccurateDouble(); 357 // Turn off the approximate double flag, since the value is now exact. 358 isApproximate = false; 359 origDouble = 0.0; 360 return; 361 } 362 363 // To get the bits from the double, use memcpy, which takes care of endianness. 364 uint64_t ieeeBits; 365 uprv_memcpy(&ieeeBits, &n, sizeof(n)); 366 int32_t exponent = static_cast<int32_t>((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff; 367 368 // Not all integers can be represented exactly for exponent > 52 369 if (exponent <= 52 && static_cast<int64_t>(n) == n) { 370 _setToLong(static_cast<int64_t>(n)); 371 return; 372 } 373 374 // 3.3219... is log2(10) 375 auto fracLength = static_cast<int32_t> ((52 - exponent) / 3.32192809489); 376 if (fracLength >= 0) { 377 int32_t i = fracLength; 378 // 1e22 is the largest exact double. 379 for (; i >= 22; i -= 22) n *= 1e22; 380 n *= DOUBLE_MULTIPLIERS[i]; 381 } else { 382 int32_t i = fracLength; 383 // 1e22 is the largest exact double. 384 for (; i <= -22; i += 22) n /= 1e22; 385 n /= DOUBLE_MULTIPLIERS[-i]; 386 } 387 auto result = static_cast<int64_t>(std::round(n)); 388 if (result != 0) { 389 _setToLong(result); 390 scale -= fracLength; 391 } 392 } 393 394 void DecimalQuantity::convertToAccurateDouble() { 395 double n = origDouble; 396 U_ASSERT(n != 0); 397 int32_t delta = origDelta; 398 setBcdToZero(); 399 400 // Call the slow oracle function (Double.toString in Java, sprintf in C++). 401 // The <float.h> constant DBL_DIG defines a platform-specific number of digits in a double. 402 // However, this tends to be too low (see #11318). Instead, we always use 14 decimal places. 403 static constexpr size_t CAP = 1 + 14 + 8; // Extra space for '+', '.', e+NNN, and '\0' 404 char dstr[CAP]; 405 snprintf(dstr, CAP, "%+1.14e", n); 406 407 // uprv_decNumberFromString() will parse the string expecting '.' as a 408 // decimal separator, however sprintf() can use ',' in certain locales. 409 // Overwrite a ',' with '.' here before proceeding. 410 char *decimalSeparator = strchr(dstr, ','); 411 if (decimalSeparator != nullptr) { 412 *decimalSeparator = '.'; 413 } 414 415 StringPiece sp(dstr); 416 DecNumberWithStorage dn; 417 stringToDecNumber(dstr, dn); 418 _setToDecNumber(dn.getAlias()); 419 420 scale += delta; 421 explicitExactDouble = true; 422 } 423 424 DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n) { 425 setBcdToZero(); 426 flags = 0; 427 428 DecNumberWithStorage dn; 429 stringToDecNumber(n, dn); 430 431 // The code path for decNumber is modeled after BigDecimal in Java. 432 if (decNumberIsNegative(dn.getAlias())) { 433 flags |= NEGATIVE_FLAG; 434 } 435 if (!decNumberIsZero(dn.getAlias())) { 436 _setToDecNumber(dn.getAlias()); 437 } 438 return *this; 439 } 440 441 void DecimalQuantity::_setToDecNumber(decNumber *n) { 442 // Java fastpaths for ints here. In C++, just always read directly from the decNumber. 443 readDecNumberToBcd(n); 444 compact(); 445 } 446 447 int64_t DecimalQuantity::toLong() const { 448 int64_t result = 0L; 449 for (int32_t magnitude = scale + precision - 1; magnitude >= 0; magnitude--) { 450 result = result * 10 + getDigitPos(magnitude - scale); 451 } 452 return result; 453 } 454 455 int64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const { 456 int64_t result = 0L; 457 int32_t magnitude = -1; 458 for (; (magnitude >= scale || (includeTrailingZeros && magnitude >= rReqPos)) && 459 magnitude >= rOptPos; magnitude--) { 460 result = result * 10 + getDigitPos(magnitude - scale); 461 } 462 return result; 463 } 464 465 double DecimalQuantity::toDouble() const { 466 if (isApproximate) { 467 return toDoubleFromOriginal(); 468 } 469 470 if (isNaN()) { 471 return NAN; 472 } else if (isInfinite()) { 473 return isNegative() ? -INFINITY : INFINITY; 474 } 475 476 int64_t tempLong = 0L; 477 int32_t lostDigits = precision - (precision < 17 ? precision : 17); 478 for (int shift = precision - 1; shift >= lostDigits; shift--) { 479 tempLong = tempLong * 10 + getDigitPos(shift); 480 } 481 double result = static_cast<double>(tempLong); 482 int32_t _scale = scale + lostDigits; 483 if (_scale >= 0) { 484 // 1e22 is the largest exact double. 485 int32_t i = _scale; 486 for (; i >= 22; i -= 22) result *= 1e22; 487 result *= DOUBLE_MULTIPLIERS[i]; 488 } else { 489 // 1e22 is the largest exact double. 490 int32_t i = _scale; 491 for (; i <= -22; i += 22) result /= 1e22; 492 result /= DOUBLE_MULTIPLIERS[-i]; 493 } 494 if (isNegative()) { result = -result; } 495 return result; 496 } 497 498 double DecimalQuantity::toDoubleFromOriginal() const { 499 double result = origDouble; 500 int32_t delta = origDelta; 501 if (delta >= 0) { 502 // 1e22 is the largest exact double. 503 for (; delta >= 22; delta -= 22) result *= 1e22; 504 result *= DOUBLE_MULTIPLIERS[delta]; 505 } else { 506 // 1e22 is the largest exact double. 507 for (; delta <= -22; delta += 22) result /= 1e22; 508 result /= DOUBLE_MULTIPLIERS[-delta]; 509 } 510 if (isNegative()) { result *= -1; } 511 return result; 512 } 513 514 void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) { 515 // The position in the BCD at which rounding will be performed; digits to the right of position 516 // will be rounded away. 517 // TODO: Andy: There was a test failure because of integer overflow here. Should I do 518 // "safe subtraction" everywhere in the code? What's the nicest way to do it? 519 int position = safeSubtract(magnitude, scale); 520 521 if (position <= 0 && !isApproximate) { 522 // All digits are to the left of the rounding magnitude. 523 } else if (precision == 0) { 524 // No rounding for zero. 525 } else { 526 // Perform rounding logic. 527 // "leading" = most significant digit to the right of rounding 528 // "trailing" = least significant digit to the left of rounding 529 int8_t leadingDigit = getDigitPos(safeSubtract(position, 1)); 530 int8_t trailingDigit = getDigitPos(position); 531 532 // Compute which section of the number we are in. 533 // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles) 534 // LOWER means we are between the bottom edge and the midpoint, like 1.391 535 // MIDPOINT means we are exactly in the middle, like 1.500 536 // UPPER means we are between the midpoint and the top edge, like 1.916 537 roundingutils::Section section = roundingutils::SECTION_MIDPOINT; 538 if (!isApproximate) { 539 if (leadingDigit < 5) { 540 section = roundingutils::SECTION_LOWER; 541 } else if (leadingDigit > 5) { 542 section = roundingutils::SECTION_UPPER; 543 } else { 544 for (int p = safeSubtract(position, 2); p >= 0; p--) { 545 if (getDigitPos(p) != 0) { 546 section = roundingutils::SECTION_UPPER; 547 break; 548 } 549 } 550 } 551 } else { 552 int32_t p = safeSubtract(position, 2); 553 int32_t minP = uprv_max(0, precision - 14); 554 if (leadingDigit == 0) { 555 section = roundingutils::SECTION_LOWER_EDGE; 556 for (; p >= minP; p--) { 557 if (getDigitPos(p) != 0) { 558 section = roundingutils::SECTION_LOWER; 559 break; 560 } 561 } 562 } else if (leadingDigit == 4) { 563 for (; p >= minP; p--) { 564 if (getDigitPos(p) != 9) { 565 section = roundingutils::SECTION_LOWER; 566 break; 567 } 568 } 569 } else if (leadingDigit == 5) { 570 for (; p >= minP; p--) { 571 if (getDigitPos(p) != 0) { 572 section = roundingutils::SECTION_UPPER; 573 break; 574 } 575 } 576 } else if (leadingDigit == 9) { 577 section = roundingutils::SECTION_UPPER_EDGE; 578 for (; p >= minP; p--) { 579 if (getDigitPos(p) != 9) { 580 section = roundingutils::SECTION_UPPER; 581 break; 582 } 583 } 584 } else if (leadingDigit < 5) { 585 section = roundingutils::SECTION_LOWER; 586 } else { 587 section = roundingutils::SECTION_UPPER; 588 } 589 590 bool roundsAtMidpoint = roundingutils::roundsAtMidpoint(roundingMode); 591 if (safeSubtract(position, 1) < precision - 14 || 592 (roundsAtMidpoint && section == roundingutils::SECTION_MIDPOINT) || 593 (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) { 594 // Oops! This means that we have to get the exact representation of the double, because 595 // the zone of uncertainty is along the rounding boundary. 596 convertToAccurateDouble(); 597 roundToMagnitude(magnitude, roundingMode, status); // start over 598 return; 599 } 600 601 // Turn off the approximate double flag, since the value is now confirmed to be exact. 602 isApproximate = false; 603 origDouble = 0.0; 604 origDelta = 0; 605 606 if (position <= 0) { 607 // All digits are to the left of the rounding magnitude. 608 return; 609 } 610 611 // Good to continue rounding. 612 if (section == -1) { section = roundingutils::SECTION_LOWER; } 613 if (section == -2) { section = roundingutils::SECTION_UPPER; } 614 } 615 616 bool roundDown = roundingutils::getRoundingDirection((trailingDigit % 2) == 0, 617 isNegative(), 618 section, 619 roundingMode, 620 status); 621 if (U_FAILURE(status)) { 622 return; 623 } 624 625 // Perform truncation 626 if (position >= precision) { 627 setBcdToZero(); 628 scale = magnitude; 629 } else { 630 shiftRight(position); 631 } 632 633 // Bubble the result to the higher digits 634 if (!roundDown) { 635 if (trailingDigit == 9) { 636 int bubblePos = 0; 637 // Note: in the long implementation, the most digits BCD can have at this point is 15, 638 // so bubblePos <= 15 and getDigitPos(bubblePos) is safe. 639 for (; getDigitPos(bubblePos) == 9; bubblePos++) {} 640 shiftRight(bubblePos); // shift off the trailing 9s 641 } 642 int8_t digit0 = getDigitPos(0); 643 U_ASSERT(digit0 != 9); 644 setDigitPos(0, static_cast<int8_t>(digit0 + 1)); 645 precision += 1; // in case an extra digit got added 646 } 647 648 compact(); 649 } 650 } 651 652 void DecimalQuantity::roundToInfinity() { 653 if (isApproximate) { 654 convertToAccurateDouble(); 655 } 656 } 657 658 void DecimalQuantity::appendDigit(int8_t value, int32_t leadingZeros, bool appendAsInteger) { 659 U_ASSERT(leadingZeros >= 0); 660 661 // Zero requires special handling to maintain the invariant that the least-significant digit 662 // in the BCD is nonzero. 663 if (value == 0) { 664 if (appendAsInteger && precision != 0) { 665 scale += leadingZeros + 1; 666 } 667 return; 668 } 669 670 // Deal with trailing zeros 671 if (scale > 0) { 672 leadingZeros += scale; 673 if (appendAsInteger) { 674 scale = 0; 675 } 676 } 677 678 // Append digit 679 shiftLeft(leadingZeros + 1); 680 setDigitPos(0, value); 681 682 // Fix scale if in integer mode 683 if (appendAsInteger) { 684 scale += leadingZeros + 1; 685 } 686 } 687 688 UnicodeString DecimalQuantity::toPlainString() const { 689 UnicodeString sb; 690 if (isNegative()) { 691 sb.append(u'-'); 692 } 693 for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) { 694 sb.append(getDigit(m) + u'0'); 695 if (m == 0) { sb.append(u'.'); } 696 } 697 return sb; 698 } 699 700 //////////////////////////////////////////////////// 701 /// End of DecimalQuantity_AbstractBCD.java /// 702 /// Start of DecimalQuantity_DualStorageBCD.java /// 703 //////////////////////////////////////////////////// 704 705 int8_t DecimalQuantity::getDigitPos(int32_t position) const { 706 if (usingBytes) { 707 if (position < 0 || position > precision) { return 0; } 708 return fBCD.bcdBytes.ptr[position]; 709 } else { 710 if (position < 0 || position >= 16) { return 0; } 711 return (int8_t) ((fBCD.bcdLong >> (position * 4)) & 0xf); 712 } 713 } 714 715 void DecimalQuantity::setDigitPos(int32_t position, int8_t value) { 716 U_ASSERT(position >= 0); 717 if (usingBytes) { 718 ensureCapacity(position + 1); 719 fBCD.bcdBytes.ptr[position] = value; 720 } else if (position >= 16) { 721 switchStorage(); 722 ensureCapacity(position + 1); 723 fBCD.bcdBytes.ptr[position] = value; 724 } else { 725 int shift = position * 4; 726 fBCD.bcdLong = (fBCD.bcdLong & ~(0xfL << shift)) | ((long) value << shift); 727 } 728 } 729 730 void DecimalQuantity::shiftLeft(int32_t numDigits) { 731 if (!usingBytes && precision + numDigits > 16) { 732 switchStorage(); 733 } 734 if (usingBytes) { 735 ensureCapacity(precision + numDigits); 736 int i = precision + numDigits - 1; 737 for (; i >= numDigits; i--) { 738 fBCD.bcdBytes.ptr[i] = fBCD.bcdBytes.ptr[i - numDigits]; 739 } 740 for (; i >= 0; i--) { 741 fBCD.bcdBytes.ptr[i] = 0; 742 } 743 } else { 744 fBCD.bcdLong <<= (numDigits * 4); 745 } 746 scale -= numDigits; 747 precision += numDigits; 748 } 749 750 void DecimalQuantity::shiftRight(int32_t numDigits) { 751 if (usingBytes) { 752 int i = 0; 753 for (; i < precision - numDigits; i++) { 754 fBCD.bcdBytes.ptr[i] = fBCD.bcdBytes.ptr[i + numDigits]; 755 } 756 for (; i < precision; i++) { 757 fBCD.bcdBytes.ptr[i] = 0; 758 } 759 } else { 760 fBCD.bcdLong >>= (numDigits * 4); 761 } 762 scale += numDigits; 763 precision -= numDigits; 764 } 765 766 void DecimalQuantity::setBcdToZero() { 767 if (usingBytes) { 768 uprv_free(fBCD.bcdBytes.ptr); 769 fBCD.bcdBytes.ptr = nullptr; 770 usingBytes = false; 771 } 772 fBCD.bcdLong = 0L; 773 scale = 0; 774 precision = 0; 775 isApproximate = false; 776 origDouble = 0; 777 origDelta = 0; 778 } 779 780 void DecimalQuantity::readIntToBcd(int32_t n) { 781 U_ASSERT(n != 0); 782 // ints always fit inside the long implementation. 783 uint64_t result = 0L; 784 int i = 16; 785 for (; n != 0; n /= 10, i--) { 786 result = (result >> 4) + ((static_cast<uint64_t>(n) % 10) << 60); 787 } 788 U_ASSERT(!usingBytes); 789 fBCD.bcdLong = result >> (i * 4); 790 scale = 0; 791 precision = 16 - i; 792 } 793 794 void DecimalQuantity::readLongToBcd(int64_t n) { 795 U_ASSERT(n != 0); 796 if (n >= 10000000000000000L) { 797 ensureCapacity(); 798 int i = 0; 799 for (; n != 0L; n /= 10L, i++) { 800 fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(n % 10); 801 } 802 U_ASSERT(usingBytes); 803 scale = 0; 804 precision = i; 805 } else { 806 uint64_t result = 0L; 807 int i = 16; 808 for (; n != 0L; n /= 10L, i--) { 809 result = (result >> 4) + ((n % 10) << 60); 810 } 811 U_ASSERT(i >= 0); 812 U_ASSERT(!usingBytes); 813 fBCD.bcdLong = result >> (i * 4); 814 scale = 0; 815 precision = 16 - i; 816 } 817 } 818 819 void DecimalQuantity::readDecNumberToBcd(decNumber *dn) { 820 if (dn->digits > 16) { 821 ensureCapacity(dn->digits); 822 for (int32_t i = 0; i < dn->digits; i++) { 823 fBCD.bcdBytes.ptr[i] = dn->lsu[i]; 824 } 825 } else { 826 uint64_t result = 0L; 827 for (int32_t i = 0; i < dn->digits; i++) { 828 result |= static_cast<uint64_t>(dn->lsu[i]) << (4 * i); 829 } 830 fBCD.bcdLong = result; 831 } 832 scale = dn->exponent; 833 precision = dn->digits; 834 } 835 836 void DecimalQuantity::compact() { 837 if (usingBytes) { 838 int32_t delta = 0; 839 for (; delta < precision && fBCD.bcdBytes.ptr[delta] == 0; delta++); 840 if (delta == precision) { 841 // Number is zero 842 setBcdToZero(); 843 return; 844 } else { 845 // Remove trailing zeros 846 shiftRight(delta); 847 } 848 849 // Compute precision 850 int32_t leading = precision - 1; 851 for (; leading >= 0 && fBCD.bcdBytes.ptr[leading] == 0; leading--); 852 precision = leading + 1; 853 854 // Switch storage mechanism if possible 855 if (precision <= 16) { 856 switchStorage(); 857 } 858 859 } else { 860 if (fBCD.bcdLong == 0L) { 861 // Number is zero 862 setBcdToZero(); 863 return; 864 } 865 866 // Compact the number (remove trailing zeros) 867 // TODO: Use a more efficient algorithm here and below. There is a logarithmic one. 868 int32_t delta = 0; 869 for (; delta < precision && getDigitPos(delta) == 0; delta++); 870 fBCD.bcdLong >>= delta * 4; 871 scale += delta; 872 873 // Compute precision 874 int32_t leading = precision - 1; 875 for (; leading >= 0 && getDigitPos(leading) == 0; leading--); 876 precision = leading + 1; 877 } 878 } 879 880 void DecimalQuantity::ensureCapacity() { 881 ensureCapacity(40); 882 } 883 884 void DecimalQuantity::ensureCapacity(int32_t capacity) { 885 if (capacity == 0) { return; } 886 int32_t oldCapacity = usingBytes ? fBCD.bcdBytes.len : 0; 887 if (!usingBytes) { 888 // TODO: There is nothing being done to check for memory allocation failures. 889 // TODO: Consider indexing by nybbles instead of bytes in C++, so that we can 890 // make these arrays half the size. 891 fBCD.bcdBytes.ptr = static_cast<int8_t*>(uprv_malloc(capacity * sizeof(int8_t))); 892 fBCD.bcdBytes.len = capacity; 893 // Initialize the byte array to zeros (this is done automatically in Java) 894 uprv_memset(fBCD.bcdBytes.ptr, 0, capacity * sizeof(int8_t)); 895 } else if (oldCapacity < capacity) { 896 auto bcd1 = static_cast<int8_t*>(uprv_malloc(capacity * 2 * sizeof(int8_t))); 897 uprv_memcpy(bcd1, fBCD.bcdBytes.ptr, oldCapacity * sizeof(int8_t)); 898 // Initialize the rest of the byte array to zeros (this is done automatically in Java) 899 uprv_memset(fBCD.bcdBytes.ptr + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t)); 900 uprv_free(fBCD.bcdBytes.ptr); 901 fBCD.bcdBytes.ptr = bcd1; 902 fBCD.bcdBytes.len = capacity * 2; 903 } 904 usingBytes = true; 905 } 906 907 void DecimalQuantity::switchStorage() { 908 if (usingBytes) { 909 // Change from bytes to long 910 uint64_t bcdLong = 0L; 911 for (int i = precision - 1; i >= 0; i--) { 912 bcdLong <<= 4; 913 bcdLong |= fBCD.bcdBytes.ptr[i]; 914 } 915 uprv_free(fBCD.bcdBytes.ptr); 916 fBCD.bcdBytes.ptr = nullptr; 917 fBCD.bcdLong = bcdLong; 918 usingBytes = false; 919 } else { 920 // Change from long to bytes 921 // Copy the long into a local variable since it will get munged when we allocate the bytes 922 uint64_t bcdLong = fBCD.bcdLong; 923 ensureCapacity(); 924 for (int i = 0; i < precision; i++) { 925 fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(bcdLong & 0xf); 926 bcdLong >>= 4; 927 } 928 U_ASSERT(usingBytes); 929 } 930 } 931 932 void DecimalQuantity::copyBcdFrom(const DecimalQuantity &other) { 933 setBcdToZero(); 934 if (other.usingBytes) { 935 ensureCapacity(other.precision); 936 uprv_memcpy(fBCD.bcdBytes.ptr, other.fBCD.bcdBytes.ptr, other.precision * sizeof(int8_t)); 937 } else { 938 fBCD.bcdLong = other.fBCD.bcdLong; 939 } 940 } 941 942 const char16_t* DecimalQuantity::checkHealth() const { 943 if (usingBytes) { 944 if (precision == 0) { return u"Zero precision but we are in byte mode"; } 945 int32_t capacity = fBCD.bcdBytes.len; 946 if (precision > capacity) { return u"Precision exceeds length of byte array"; } 947 if (getDigitPos(precision - 1) == 0) { return u"Most significant digit is zero in byte mode"; } 948 if (getDigitPos(0) == 0) { return u"Least significant digit is zero in long mode"; } 949 for (int i = 0; i < precision; i++) { 950 if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in byte array"; } 951 if (getDigitPos(i) < 0) { return u"Digit below 0 in byte array"; } 952 } 953 for (int i = precision; i < capacity; i++) { 954 if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in byte array"; } 955 } 956 } else { 957 if (precision == 0 && fBCD.bcdLong != 0) { 958 return u"Value in bcdLong even though precision is zero"; 959 } 960 if (precision > 16) { return u"Precision exceeds length of long"; } 961 if (precision != 0 && getDigitPos(precision - 1) == 0) { 962 return u"Most significant digit is zero in long mode"; 963 } 964 if (precision != 0 && getDigitPos(0) == 0) { 965 return u"Least significant digit is zero in long mode"; 966 } 967 for (int i = 0; i < precision; i++) { 968 if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in long"; } 969 if (getDigitPos(i) < 0) { return u"Digit below 0 in long (?!)"; } 970 } 971 for (int i = precision; i < 16; i++) { 972 if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in long"; } 973 } 974 } 975 976 // No error 977 return nullptr; 978 } 979 980 UnicodeString DecimalQuantity::toString() const { 981 MaybeStackArray<char, 30> digits(precision + 1); 982 for (int32_t i = 0; i < precision; i++) { 983 digits[i] = getDigitPos(precision - i - 1) + '0'; 984 } 985 digits[precision] = 0; // terminate buffer 986 char buffer8[100]; 987 snprintf( 988 buffer8, 989 sizeof(buffer8), 990 "<DecimalQuantity %d:%d:%d:%d %s %s%s%d>", 991 (lOptPos > 999 ? 999 : lOptPos), 992 lReqPos, 993 rReqPos, 994 (rOptPos < -999 ? -999 : rOptPos), 995 (usingBytes ? "bytes" : "long"), 996 (precision == 0 ? "0" : digits.getAlias()), 997 "E", 998 scale); 999 return UnicodeString(buffer8, -1, US_INV); 1000 } 1001 1002 UnicodeString DecimalQuantity::toNumberString() const { 1003 MaybeStackArray<char, 30> digits(precision + 11); 1004 for (int32_t i = 0; i < precision; i++) { 1005 digits[i] = getDigitPos(precision - i - 1) + '0'; 1006 } 1007 snprintf(digits.getAlias() + precision, 11, "E%d", scale); 1008 return UnicodeString(digits.getAlias(), -1, US_INV); 1009 } 1010 1011 #endif /* #if !UCONFIG_NO_FORMATTING */ 1012