number_decimalquantity.cpp (47527B)
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 7 8 #include <cstdlib> 9 #include <cmath> 10 #include <limits> 11 #include <stdlib.h> 12 13 #include "unicode/plurrule.h" 14 #include "cmemory.h" 15 #include "number_decnum.h" 16 #include "putilimp.h" 17 #include "number_decimalquantity.h" 18 #include "number_roundingutils.h" 19 #ifdef JS_HAS_INTL_API 20 #include "double-conversion/double-conversion.h" 21 #else 22 #include "double-conversion.h" 23 #endif 24 #include "charstr.h" 25 #include "number_utils.h" 26 #include "uassert.h" 27 #include "util.h" 28 29 using namespace icu; 30 using namespace icu::number; 31 using namespace icu::number::impl; 32 33 #ifdef JS_HAS_INTL_API 34 using double_conversion::DoubleToStringConverter; 35 using double_conversion::StringToDoubleConverter; 36 #else 37 using icu::double_conversion::DoubleToStringConverter; 38 using icu::double_conversion::StringToDoubleConverter; 39 #endif 40 41 namespace { 42 43 int8_t NEGATIVE_FLAG = 1; 44 int8_t INFINITY_FLAG = 2; 45 int8_t NAN_FLAG = 4; 46 47 /** Helper function for safe subtraction (no overflow). */ 48 inline int32_t safeSubtract(int32_t a, int32_t b) { 49 // Note: In C++, signed integer subtraction is undefined behavior. 50 int32_t diff = static_cast<int32_t>(static_cast<uint32_t>(a) - static_cast<uint32_t>(b)); 51 if (b < 0 && diff < a) { return INT32_MAX; } 52 if (b > 0 && diff > a) { return INT32_MIN; } 53 return diff; 54 } 55 56 double DOUBLE_MULTIPLIERS[] = { 57 1e0, 58 1e1, 59 1e2, 60 1e3, 61 1e4, 62 1e5, 63 1e6, 64 1e7, 65 1e8, 66 1e9, 67 1e10, 68 1e11, 69 1e12, 70 1e13, 71 1e14, 72 1e15, 73 1e16, 74 1e17, 75 1e18, 76 1e19, 77 1e20, 78 1e21}; 79 80 } // namespace 81 82 icu::IFixedDecimal::~IFixedDecimal() = default; 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(DecimalQuantity&& src) noexcept { 102 *this = std::move(src); 103 } 104 105 DecimalQuantity &DecimalQuantity::operator=(const DecimalQuantity &other) { 106 if (this == &other) { 107 return *this; 108 } 109 copyBcdFrom(other); 110 copyFieldsFrom(other); 111 return *this; 112 } 113 114 DecimalQuantity& DecimalQuantity::operator=(DecimalQuantity&& src) noexcept { 115 if (this == &src) { 116 return *this; 117 } 118 moveBcdFrom(src); 119 copyFieldsFrom(src); 120 return *this; 121 } 122 123 void DecimalQuantity::copyFieldsFrom(const DecimalQuantity& other) { 124 bogus = other.bogus; 125 lReqPos = other.lReqPos; 126 rReqPos = other.rReqPos; 127 scale = other.scale; 128 precision = other.precision; 129 flags = other.flags; 130 origDouble = other.origDouble; 131 origDelta = other.origDelta; 132 isApproximate = other.isApproximate; 133 exponent = other.exponent; 134 } 135 136 void DecimalQuantity::clear() { 137 lReqPos = 0; 138 rReqPos = 0; 139 flags = 0; 140 setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data 141 } 142 143 void DecimalQuantity::decreaseMinIntegerTo(int32_t minInt) { 144 // Validation should happen outside of DecimalQuantity, e.g., in the Precision class. 145 U_ASSERT(minInt >= 0); 146 147 if (lReqPos > minInt) { 148 lReqPos = minInt; 149 } 150 } 151 152 void DecimalQuantity::increaseMinIntegerTo(int32_t minInt) { 153 // Validation should happen outside of DecimalQuantity, e.g., in the Precision class. 154 U_ASSERT(minInt >= 0); 155 156 // Special behavior: do not set minInt to be less than what is already set. 157 // This is so significant digits rounding can set the integer length. 158 if (lReqPos < minInt) { 159 lReqPos = minInt; 160 } 161 } 162 163 void DecimalQuantity::setMinFraction(int32_t minFrac) { 164 // Validation should happen outside of DecimalQuantity, e.g., in the Precision class. 165 U_ASSERT(minFrac >= 0); 166 167 // Save values into internal state 168 // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE 169 rReqPos = -minFrac; 170 } 171 172 void DecimalQuantity::applyMaxInteger(int32_t maxInt) { 173 // Validation should happen outside of DecimalQuantity, e.g., in the Precision class. 174 U_ASSERT(maxInt >= 0); 175 176 if (precision == 0) { 177 return; 178 } 179 180 if (maxInt <= scale) { 181 setBcdToZero(); 182 return; 183 } 184 185 int32_t magnitude = getMagnitude(); 186 if (maxInt <= magnitude) { 187 popFromLeft(magnitude - maxInt + 1); 188 compact(); 189 } 190 } 191 192 uint64_t DecimalQuantity::getPositionFingerprint() const { 193 uint64_t fingerprint = 0; 194 fingerprint ^= (lReqPos << 16); 195 fingerprint ^= (static_cast<uint64_t>(rReqPos) << 32); 196 return fingerprint; 197 } 198 199 void DecimalQuantity::roundToIncrement( 200 uint64_t increment, 201 digits_t magnitude, 202 RoundingMode roundingMode, 203 UErrorCode& status) { 204 // Do not call this method with an increment having only a 1 or a 5 digit! 205 // Use a more efficient call to either roundToMagnitude() or roundToNickel(). 206 // Check a few popular rounding increments; a more thorough check is in Java. 207 U_ASSERT(increment != 1); 208 U_ASSERT(increment != 5); 209 210 DecimalQuantity incrementDQ; 211 incrementDQ.setToLong(increment); 212 incrementDQ.adjustMagnitude(magnitude); 213 DecNum incrementDN; 214 incrementDQ.toDecNum(incrementDN, status); 215 if (U_FAILURE(status)) { return; } 216 217 // Divide this DecimalQuantity by the increment, round, then multiply back. 218 divideBy(incrementDN, status); 219 if (U_FAILURE(status)) { return; } 220 roundToMagnitude(0, roundingMode, status); 221 if (U_FAILURE(status)) { return; } 222 multiplyBy(incrementDN, status); 223 if (U_FAILURE(status)) { return; } 224 } 225 226 void DecimalQuantity::multiplyBy(const DecNum& multiplicand, UErrorCode& status) { 227 if (isZeroish()) { 228 return; 229 } 230 // Convert to DecNum, multiply, and convert back. 231 DecNum decnum; 232 toDecNum(decnum, status); 233 if (U_FAILURE(status)) { return; } 234 decnum.multiplyBy(multiplicand, status); 235 if (U_FAILURE(status)) { return; } 236 setToDecNum(decnum, status); 237 } 238 239 void DecimalQuantity::divideBy(const DecNum& divisor, UErrorCode& status) { 240 if (isZeroish()) { 241 return; 242 } 243 // Convert to DecNum, multiply, and convert back. 244 DecNum decnum; 245 toDecNum(decnum, status); 246 if (U_FAILURE(status)) { return; } 247 decnum.divideBy(divisor, status); 248 if (U_FAILURE(status)) { return; } 249 setToDecNum(decnum, status); 250 } 251 252 void DecimalQuantity::negate() { 253 flags ^= NEGATIVE_FLAG; 254 } 255 256 int32_t DecimalQuantity::getMagnitude() const { 257 U_ASSERT(precision != 0); 258 return scale + precision - 1; 259 } 260 261 bool DecimalQuantity::adjustMagnitude(int32_t delta) { 262 if (precision != 0) { 263 // i.e., scale += delta; origDelta += delta 264 bool overflow = uprv_add32_overflow(scale, delta, &scale); 265 overflow = uprv_add32_overflow(origDelta, delta, &origDelta) || overflow; 266 // Make sure that precision + scale won't overflow, either 267 int32_t dummy; 268 overflow = overflow || uprv_add32_overflow(scale, precision, &dummy); 269 return overflow; 270 } 271 return false; 272 } 273 274 int32_t DecimalQuantity::adjustToZeroScale() { 275 int32_t retval = scale; 276 scale = 0; 277 return retval; 278 } 279 280 double DecimalQuantity::getPluralOperand(PluralOperand operand) const { 281 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 282 // See the comment at the top of this file explaining the "isApproximate" field. 283 U_ASSERT(!isApproximate); 284 285 switch (operand) { 286 case PLURAL_OPERAND_I: 287 // Invert the negative sign if necessary 288 return static_cast<double>(isNegative() ? -toLong(true) : toLong(true)); 289 case PLURAL_OPERAND_F: 290 return static_cast<double>(toFractionLong(true)); 291 case PLURAL_OPERAND_T: 292 return static_cast<double>(toFractionLong(false)); 293 case PLURAL_OPERAND_V: 294 return fractionCount(); 295 case PLURAL_OPERAND_W: 296 return fractionCountWithoutTrailingZeros(); 297 case PLURAL_OPERAND_E: 298 return static_cast<double>(getExponent()); 299 case PLURAL_OPERAND_C: 300 // Plural operand `c` is currently an alias for `e`. 301 return static_cast<double>(getExponent()); 302 default: 303 return std::abs(toDouble()); 304 } 305 } 306 307 int32_t DecimalQuantity::getExponent() const { 308 return exponent; 309 } 310 311 void DecimalQuantity::adjustExponent(int delta) { 312 exponent = exponent + delta; 313 } 314 315 void DecimalQuantity::resetExponent() { 316 adjustMagnitude(exponent); 317 exponent = 0; 318 } 319 320 bool DecimalQuantity::hasIntegerValue() const { 321 return scale >= 0; 322 } 323 324 int32_t DecimalQuantity::getUpperDisplayMagnitude() const { 325 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 326 // See the comment in the header file explaining the "isApproximate" field. 327 U_ASSERT(!isApproximate); 328 329 int32_t magnitude = scale + precision; 330 int32_t result = (lReqPos > magnitude) ? lReqPos : magnitude; 331 return result - 1; 332 } 333 334 int32_t DecimalQuantity::getLowerDisplayMagnitude() const { 335 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 336 // See the comment in the header file explaining the "isApproximate" field. 337 U_ASSERT(!isApproximate); 338 339 int32_t magnitude = scale; 340 int32_t result = (rReqPos < magnitude) ? rReqPos : magnitude; 341 return result; 342 } 343 344 int8_t DecimalQuantity::getDigit(int32_t magnitude) const { 345 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 346 // See the comment at the top of this file explaining the "isApproximate" field. 347 U_ASSERT(!isApproximate); 348 349 return getDigitPos(magnitude - scale); 350 } 351 352 int32_t DecimalQuantity::fractionCount() const { 353 int32_t fractionCountWithExponent = -getLowerDisplayMagnitude() - exponent; 354 return fractionCountWithExponent > 0 ? fractionCountWithExponent : 0; 355 } 356 357 int32_t DecimalQuantity::fractionCountWithoutTrailingZeros() const { 358 int32_t fractionCountWithExponent = -scale - exponent; 359 return fractionCountWithExponent > 0 ? fractionCountWithExponent : 0; // max(-fractionCountWithExponent, 0) 360 } 361 362 bool DecimalQuantity::isNegative() const { 363 return (flags & NEGATIVE_FLAG) != 0; 364 } 365 366 Signum DecimalQuantity::signum() const { 367 bool isZero = (isZeroish() && !isInfinite()); 368 bool isNeg = isNegative(); 369 if (isZero && isNeg) { 370 return SIGNUM_NEG_ZERO; 371 } else if (isZero) { 372 return SIGNUM_POS_ZERO; 373 } else if (isNeg) { 374 return SIGNUM_NEG; 375 } else { 376 return SIGNUM_POS; 377 } 378 } 379 380 bool DecimalQuantity::isInfinite() const { 381 return (flags & INFINITY_FLAG) != 0; 382 } 383 384 bool DecimalQuantity::isNaN() const { 385 return (flags & NAN_FLAG) != 0; 386 } 387 388 bool DecimalQuantity::isZeroish() const { 389 return precision == 0; 390 } 391 392 DecimalQuantity &DecimalQuantity::setToInt(int32_t n) { 393 setBcdToZero(); 394 flags = 0; 395 if (n == INT32_MIN) { 396 flags |= NEGATIVE_FLAG; 397 // leave as INT32_MIN; handled below in _setToInt() 398 } else if (n < 0) { 399 flags |= NEGATIVE_FLAG; 400 n = -n; 401 } 402 if (n != 0) { 403 _setToInt(n); 404 compact(); 405 } 406 return *this; 407 } 408 409 void DecimalQuantity::_setToInt(int32_t n) { 410 if (n == INT32_MIN) { 411 readLongToBcd(-static_cast<int64_t>(n)); 412 } else { 413 readIntToBcd(n); 414 } 415 } 416 417 DecimalQuantity &DecimalQuantity::setToLong(int64_t n) { 418 setBcdToZero(); 419 flags = 0; 420 if (n < 0 && n > INT64_MIN) { 421 flags |= NEGATIVE_FLAG; 422 n = -n; 423 } 424 if (n != 0) { 425 _setToLong(n); 426 compact(); 427 } 428 return *this; 429 } 430 431 void DecimalQuantity::_setToLong(int64_t n) { 432 if (n == INT64_MIN) { 433 DecNum decnum; 434 UErrorCode localStatus = U_ZERO_ERROR; 435 decnum.setTo("9.223372036854775808E+18", localStatus); 436 if (U_FAILURE(localStatus)) { return; } // unexpected 437 flags |= NEGATIVE_FLAG; 438 readDecNumberToBcd(decnum); 439 } else if (n <= INT32_MAX) { 440 readIntToBcd(static_cast<int32_t>(n)); 441 } else { 442 readLongToBcd(n); 443 } 444 } 445 446 DecimalQuantity &DecimalQuantity::setToDouble(double n) { 447 setBcdToZero(); 448 flags = 0; 449 // signbit() from <math.h> handles +0.0 vs -0.0 450 if (std::signbit(n)) { 451 flags |= NEGATIVE_FLAG; 452 n = -n; 453 } 454 if (std::isnan(n) != 0) { 455 flags |= NAN_FLAG; 456 } else if (std::isfinite(n) == 0) { 457 flags |= INFINITY_FLAG; 458 } else if (n != 0) { 459 _setToDoubleFast(n); 460 compact(); 461 } 462 return *this; 463 } 464 465 void DecimalQuantity::_setToDoubleFast(double n) { 466 isApproximate = true; 467 origDouble = n; 468 origDelta = 0; 469 470 // Make sure the double is an IEEE 754 double. If not, fall back to the slow path right now. 471 // TODO: Make a fast path for other types of doubles. 472 if (!std::numeric_limits<double>::is_iec559) { 473 convertToAccurateDouble(); 474 return; 475 } 476 477 // To get the bits from the double, use memcpy, which takes care of endianness. 478 uint64_t ieeeBits; 479 uprv_memcpy(&ieeeBits, &n, sizeof(n)); 480 int32_t exponent = static_cast<int32_t>((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff; 481 482 // Not all integers can be represented exactly for exponent > 52 483 if (exponent <= 52 && static_cast<int64_t>(n) == n) { 484 _setToLong(static_cast<int64_t>(n)); 485 return; 486 } 487 488 if (exponent == -1023 || exponent == 1024) { 489 // The extreme values of exponent are special; use slow path. 490 convertToAccurateDouble(); 491 return; 492 } 493 494 // 3.3219... is log2(10) 495 auto fracLength = static_cast<int32_t> ((52 - exponent) / 3.32192809488736234787031942948939017586); 496 if (fracLength >= 0) { 497 int32_t i = fracLength; 498 // 1e22 is the largest exact double. 499 for (; i >= 22; i -= 22) n *= 1e22; 500 n *= DOUBLE_MULTIPLIERS[i]; 501 } else { 502 int32_t i = fracLength; 503 // 1e22 is the largest exact double. 504 for (; i <= -22; i += 22) n /= 1e22; 505 n /= DOUBLE_MULTIPLIERS[-i]; 506 } 507 auto result = static_cast<int64_t>(uprv_round(n)); 508 if (result != 0) { 509 _setToLong(result); 510 scale -= fracLength; 511 } 512 } 513 514 void DecimalQuantity::convertToAccurateDouble() { 515 U_ASSERT(origDouble != 0); 516 int32_t delta = origDelta; 517 518 // Call the slow oracle function (Double.toString in Java, DoubleToAscii in C++). 519 char buffer[DoubleToStringConverter::kBase10MaximalLength + 1]; 520 bool sign; // unused; always positive 521 int32_t length; 522 int32_t point; 523 DoubleToStringConverter::DoubleToAscii( 524 origDouble, 525 DoubleToStringConverter::DtoaMode::SHORTEST, 526 0, 527 buffer, 528 sizeof(buffer), 529 &sign, 530 &length, 531 &point 532 ); 533 534 setBcdToZero(); 535 readDoubleConversionToBcd(buffer, length, point); 536 scale += delta; 537 explicitExactDouble = true; 538 } 539 540 DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n, UErrorCode& status) { 541 setBcdToZero(); 542 flags = 0; 543 544 // Compute the decNumber representation 545 DecNum decnum; 546 decnum.setTo(n, status); 547 548 _setToDecNum(decnum, status); 549 return *this; 550 } 551 552 DecimalQuantity& DecimalQuantity::setToDecNum(const DecNum& decnum, UErrorCode& status) { 553 setBcdToZero(); 554 flags = 0; 555 556 _setToDecNum(decnum, status); 557 return *this; 558 } 559 560 void DecimalQuantity::_setToDecNum(const DecNum& decnum, UErrorCode& status) { 561 if (U_FAILURE(status)) { return; } 562 if (decnum.isNegative()) { 563 flags |= NEGATIVE_FLAG; 564 } 565 if (decnum.isNaN()) { 566 flags |= NAN_FLAG; 567 } else if (decnum.isInfinity()) { 568 flags |= INFINITY_FLAG; 569 } else if (!decnum.isZero()) { 570 readDecNumberToBcd(decnum); 571 compact(); 572 } 573 } 574 575 DecimalQuantity DecimalQuantity::fromExponentString(UnicodeString num, UErrorCode& status) { 576 if (num.indexOf(u'e') >= 0 || num.indexOf(u'c') >= 0 577 || num.indexOf(u'E') >= 0 || num.indexOf(u'C') >= 0) { 578 int32_t ePos = num.lastIndexOf('e'); 579 if (ePos < 0) { 580 ePos = num.lastIndexOf('c'); 581 } 582 if (ePos < 0) { 583 ePos = num.lastIndexOf('E'); 584 } 585 if (ePos < 0) { 586 ePos = num.lastIndexOf('C'); 587 } 588 int32_t expNumPos = ePos + 1; 589 UnicodeString exponentStr = num.tempSubString(expNumPos, num.length() - expNumPos); 590 591 // parse exponentStr into exponent, but note that parseAsciiInteger doesn't handle the minus sign 592 bool isExpStrNeg = num[expNumPos] == u'-'; 593 int32_t exponentParsePos = isExpStrNeg ? 1 : 0; 594 int32_t exponent = ICU_Utility::parseAsciiInteger(exponentStr, exponentParsePos); 595 exponent = isExpStrNeg ? -exponent : exponent; 596 597 // Compute the decNumber representation 598 UnicodeString fractionStr = num.tempSubString(0, ePos); 599 CharString fracCharStr = CharString(); 600 fracCharStr.appendInvariantChars(fractionStr, status); 601 DecNum decnum; 602 decnum.setTo(fracCharStr.toStringPiece(), status); 603 604 // Clear and set this DecimalQuantity instance 605 DecimalQuantity dq; 606 dq.setToDecNum(decnum, status); 607 int32_t numFracDigit = getVisibleFractionCount(fractionStr); 608 dq.setMinFraction(numFracDigit); 609 dq.adjustExponent(exponent); 610 611 return dq; 612 } else { 613 DecimalQuantity dq; 614 int numFracDigit = getVisibleFractionCount(num); 615 616 CharString numCharStr = CharString(); 617 numCharStr.appendInvariantChars(num, status); 618 dq.setToDecNumber(numCharStr.toStringPiece(), status); 619 620 dq.setMinFraction(numFracDigit); 621 return dq; 622 } 623 } 624 625 int32_t DecimalQuantity::getVisibleFractionCount(UnicodeString value) { 626 int decimalPos = value.indexOf('.') + 1; 627 if (decimalPos == 0) { 628 return 0; 629 } else { 630 return value.length() - decimalPos; 631 } 632 } 633 634 int64_t DecimalQuantity::toLong(bool truncateIfOverflow) const { 635 // NOTE: Call sites should be guarded by fitsInLong(), like this: 636 // if (dq.fitsInLong()) { /* use dq.toLong() */ } else { /* use some fallback */ } 637 // Fallback behavior upon truncateIfOverflow is to truncate at 17 digits. 638 uint64_t result = 0L; 639 int32_t upperMagnitude = exponent + scale + precision - 1; 640 if (truncateIfOverflow) { 641 upperMagnitude = std::min(upperMagnitude, 17); 642 } 643 for (int32_t magnitude = upperMagnitude; magnitude >= 0; magnitude--) { 644 result = result * 10 + getDigitPos(magnitude - scale - exponent); 645 } 646 if (isNegative()) { 647 return static_cast<int64_t>(0LL - result); // i.e., -result 648 } 649 return static_cast<int64_t>(result); 650 } 651 652 uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const { 653 uint64_t result = 0L; 654 int32_t magnitude = -1 - exponent; 655 int32_t lowerMagnitude = scale; 656 if (includeTrailingZeros) { 657 lowerMagnitude = std::min(lowerMagnitude, rReqPos); 658 } 659 for (; magnitude >= lowerMagnitude && result <= 1e18L; magnitude--) { 660 result = result * 10 + getDigitPos(magnitude - scale); 661 } 662 // Remove trailing zeros; this can happen during integer overflow cases. 663 if (!includeTrailingZeros) { 664 while (result > 0 && (result % 10) == 0) { 665 result /= 10; 666 } 667 } 668 return result; 669 } 670 671 bool DecimalQuantity::fitsInLong(bool ignoreFraction) const { 672 if (isInfinite() || isNaN()) { 673 return false; 674 } 675 if (isZeroish()) { 676 return true; 677 } 678 if (exponent + scale < 0 && !ignoreFraction) { 679 return false; 680 } 681 int magnitude = getMagnitude(); 682 if (magnitude < 18) { 683 return true; 684 } 685 if (magnitude > 18) { 686 return false; 687 } 688 // Hard case: the magnitude is 10^18. 689 // The largest int64 is: 9,223,372,036,854,775,807 690 for (int p = 0; p < precision; p++) { 691 int8_t digit = getDigit(18 - p); 692 static int8_t INT64_BCD[] = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 }; 693 if (digit < INT64_BCD[p]) { 694 return true; 695 } else if (digit > INT64_BCD[p]) { 696 return false; 697 } 698 } 699 // Exactly equal to max long plus one. 700 return isNegative(); 701 } 702 703 double DecimalQuantity::toDouble() const { 704 // If this assertion fails, you need to call roundToInfinity() or some other rounding method. 705 // See the comment in the header file explaining the "isApproximate" field. 706 U_ASSERT(!isApproximate); 707 708 if (isNaN()) { 709 return NAN; 710 } else if (isInfinite()) { 711 return isNegative() ? -INFINITY : INFINITY; 712 } 713 714 // We are processing well-formed input, so we don't need any special options to StringToDoubleConverter. 715 StringToDoubleConverter converter(0, 0, 0, "", ""); 716 UnicodeString numberString = this->toScientificString(); 717 int32_t count; 718 return converter.StringToDouble( 719 reinterpret_cast<const uint16_t*>(numberString.getBuffer()), 720 numberString.length(), 721 &count); 722 } 723 724 DecNum& DecimalQuantity::toDecNum(DecNum& output, UErrorCode& status) const { 725 // Special handling for zero 726 if (precision == 0) { 727 output.setTo("0", status); 728 return output; 729 } 730 731 // Use the BCD constructor. We need to do a little bit of work to convert, though. 732 // The decNumber constructor expects most-significant first, but we store least-significant first. 733 MaybeStackArray<uint8_t, 20> ubcd(precision, status); 734 if (U_FAILURE(status)) { 735 return output; 736 } 737 for (int32_t m = 0; m < precision; m++) { 738 ubcd[precision - m - 1] = static_cast<uint8_t>(getDigitPos(m)); 739 } 740 output.setTo(ubcd.getAlias(), precision, scale, isNegative(), status); 741 return output; 742 } 743 744 void DecimalQuantity::truncate() { 745 if (scale < 0) { 746 shiftRight(-scale); 747 scale = 0; 748 compact(); 749 } 750 } 751 752 void DecimalQuantity::roundToNickel(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) { 753 roundToMagnitude(magnitude, roundingMode, true, status); 754 } 755 756 void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) { 757 roundToMagnitude(magnitude, roundingMode, false, status); 758 } 759 760 void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, bool nickel, UErrorCode& status) { 761 // The position in the BCD at which rounding will be performed; digits to the right of position 762 // will be rounded away. 763 int position = safeSubtract(magnitude, scale); 764 765 // "trailing" = least significant digit to the left of rounding 766 int8_t trailingDigit = getDigitPos(position); 767 768 if (position <= 0 && !isApproximate && (!nickel || trailingDigit == 0 || trailingDigit == 5)) { 769 // All digits are to the left of the rounding magnitude. 770 } else if (precision == 0) { 771 // No rounding for zero. 772 } else { 773 // Perform rounding logic. 774 // "leading" = most significant digit to the right of rounding 775 int8_t leadingDigit = getDigitPos(safeSubtract(position, 1)); 776 777 // Compute which section of the number we are in. 778 // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles) 779 // LOWER means we are between the bottom edge and the midpoint, like 1.391 780 // MIDPOINT means we are exactly in the middle, like 1.500 781 // UPPER means we are between the midpoint and the top edge, like 1.916 782 roundingutils::Section section; 783 if (!isApproximate) { 784 if (nickel && trailingDigit != 2 && trailingDigit != 7) { 785 // Nickel rounding, and not at .02x or .07x 786 if (trailingDigit < 2) { 787 // .00, .01 => down to .00 788 section = roundingutils::SECTION_LOWER; 789 } else if (trailingDigit < 5) { 790 // .03, .04 => up to .05 791 section = roundingutils::SECTION_UPPER; 792 } else if (trailingDigit < 7) { 793 // .05, .06 => down to .05 794 section = roundingutils::SECTION_LOWER; 795 } else { 796 // .08, .09 => up to .10 797 section = roundingutils::SECTION_UPPER; 798 } 799 } else if (leadingDigit < 5) { 800 // Includes nickel rounding .020-.024 and .070-.074 801 section = roundingutils::SECTION_LOWER; 802 } else if (leadingDigit > 5) { 803 // Includes nickel rounding .026-.029 and .076-.079 804 section = roundingutils::SECTION_UPPER; 805 } else { 806 // Includes nickel rounding .025 and .075 807 section = roundingutils::SECTION_MIDPOINT; 808 for (int p = safeSubtract(position, 2); p >= 0; p--) { 809 if (getDigitPos(p) != 0) { 810 section = roundingutils::SECTION_UPPER; 811 break; 812 } 813 } 814 } 815 } else { 816 int32_t p = safeSubtract(position, 2); 817 int32_t minP = uprv_max(0, precision - 14); 818 if (leadingDigit == 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) { 819 section = roundingutils::SECTION_LOWER_EDGE; 820 for (; p >= minP; p--) { 821 if (getDigitPos(p) != 0) { 822 section = roundingutils::SECTION_LOWER; 823 break; 824 } 825 } 826 } else if (leadingDigit == 4 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) { 827 section = roundingutils::SECTION_MIDPOINT; 828 for (; p >= minP; p--) { 829 if (getDigitPos(p) != 9) { 830 section = roundingutils::SECTION_LOWER; 831 break; 832 } 833 } 834 } else if (leadingDigit == 5 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) { 835 section = roundingutils::SECTION_MIDPOINT; 836 for (; p >= minP; p--) { 837 if (getDigitPos(p) != 0) { 838 section = roundingutils::SECTION_UPPER; 839 break; 840 } 841 } 842 } else if (leadingDigit == 9 && (!nickel || trailingDigit == 4 || trailingDigit == 9)) { 843 section = roundingutils::SECTION_UPPER_EDGE; 844 for (; p >= minP; p--) { 845 if (getDigitPos(p) != 9) { 846 section = roundingutils::SECTION_UPPER; 847 break; 848 } 849 } 850 } else if (nickel && trailingDigit != 2 && trailingDigit != 7) { 851 // Nickel rounding, and not at .02x or .07x 852 if (trailingDigit < 2) { 853 // .00, .01 => down to .00 854 section = roundingutils::SECTION_LOWER; 855 } else if (trailingDigit < 5) { 856 // .03, .04 => up to .05 857 section = roundingutils::SECTION_UPPER; 858 } else if (trailingDigit < 7) { 859 // .05, .06 => down to .05 860 section = roundingutils::SECTION_LOWER; 861 } else { 862 // .08, .09 => up to .10 863 section = roundingutils::SECTION_UPPER; 864 } 865 } else if (leadingDigit < 5) { 866 // Includes nickel rounding .020-.024 and .070-.074 867 section = roundingutils::SECTION_LOWER; 868 } else { 869 // Includes nickel rounding .026-.029 and .076-.079 870 section = roundingutils::SECTION_UPPER; 871 } 872 873 bool roundsAtMidpoint = roundingutils::roundsAtMidpoint(roundingMode); 874 if (safeSubtract(position, 1) < precision - 14 || 875 (roundsAtMidpoint && section == roundingutils::SECTION_MIDPOINT) || 876 (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) { 877 // Oops! This means that we have to get the exact representation of the double, 878 // because the zone of uncertainty is along the rounding boundary. 879 convertToAccurateDouble(); 880 roundToMagnitude(magnitude, roundingMode, nickel, status); // start over 881 return; 882 } 883 884 // Turn off the approximate double flag, since the value is now confirmed to be exact. 885 isApproximate = false; 886 origDouble = 0.0; 887 origDelta = 0; 888 889 if (position <= 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) { 890 // All digits are to the left of the rounding magnitude. 891 return; 892 } 893 894 // Good to continue rounding. 895 if (section == -1) { section = roundingutils::SECTION_LOWER; } 896 if (section == -2) { section = roundingutils::SECTION_UPPER; } 897 } 898 899 // Nickel rounding "half even" goes to the nearest whole (away from the 5). 900 bool isEven = nickel 901 ? (trailingDigit < 2 || trailingDigit > 7 902 || (trailingDigit == 2 && section != roundingutils::SECTION_UPPER) 903 || (trailingDigit == 7 && section == roundingutils::SECTION_UPPER)) 904 : (trailingDigit % 2) == 0; 905 906 bool roundDown = roundingutils::getRoundingDirection(isEven, 907 isNegative(), 908 section, 909 roundingMode, 910 status); 911 if (U_FAILURE(status)) { 912 return; 913 } 914 915 // Perform truncation 916 if (position >= precision) { 917 U_ASSERT(trailingDigit == 0); 918 setBcdToZero(); 919 scale = magnitude; 920 } else { 921 shiftRight(position); 922 } 923 924 if (nickel) { 925 if (trailingDigit < 5 && roundDown) { 926 setDigitPos(0, 0); 927 compact(); 928 return; 929 } else if (trailingDigit >= 5 && !roundDown) { 930 setDigitPos(0, 9); 931 trailingDigit = 9; 932 // do not return: use the bubbling logic below 933 } else { 934 setDigitPos(0, 5); 935 // If the quantity was set to 0, we may need to restore a digit. 936 if (precision == 0) { 937 precision = 1; 938 } 939 // compact not necessary: digit at position 0 is nonzero 940 return; 941 } 942 } 943 944 // Bubble the result to the higher digits 945 if (!roundDown) { 946 if (trailingDigit == 9) { 947 int bubblePos = 0; 948 // Note: in the long implementation, the most digits BCD can have at this point is 949 // 15, so bubblePos <= 15 and getDigitPos(bubblePos) is safe. 950 for (; getDigitPos(bubblePos) == 9; bubblePos++) {} 951 shiftRight(bubblePos); // shift off the trailing 9s 952 } 953 int8_t digit0 = getDigitPos(0); 954 U_ASSERT(digit0 != 9); 955 setDigitPos(0, static_cast<int8_t>(digit0 + 1)); 956 precision += 1; // in case an extra digit got added 957 } 958 959 compact(); 960 } 961 } 962 963 void DecimalQuantity::roundToInfinity() { 964 if (isApproximate) { 965 convertToAccurateDouble(); 966 } 967 } 968 969 void DecimalQuantity::appendDigit(int8_t value, int32_t leadingZeros, bool appendAsInteger) { 970 U_ASSERT(leadingZeros >= 0); 971 972 // Zero requires special handling to maintain the invariant that the least-significant digit 973 // in the BCD is nonzero. 974 if (value == 0) { 975 if (appendAsInteger && precision != 0) { 976 scale += leadingZeros + 1; 977 } 978 return; 979 } 980 981 // Deal with trailing zeros 982 if (scale > 0) { 983 leadingZeros += scale; 984 if (appendAsInteger) { 985 scale = 0; 986 } 987 } 988 989 // Append digit 990 shiftLeft(leadingZeros + 1); 991 setDigitPos(0, value); 992 993 // Fix scale if in integer mode 994 if (appendAsInteger) { 995 scale += leadingZeros + 1; 996 } 997 } 998 999 UnicodeString DecimalQuantity::toPlainString() const { 1000 U_ASSERT(!isApproximate); 1001 UnicodeString sb; 1002 if (isNegative()) { 1003 sb.append(u'-'); 1004 } 1005 if (precision == 0) { 1006 sb.append(u'0'); 1007 return sb; 1008 } 1009 int32_t upper = scale + precision + exponent - 1; 1010 int32_t lower = scale + exponent; 1011 if (upper < lReqPos - 1) { 1012 upper = lReqPos - 1; 1013 } 1014 if (lower > rReqPos) { 1015 lower = rReqPos; 1016 } 1017 int32_t p = upper; 1018 if (p < 0) { 1019 sb.append(u'0'); 1020 } 1021 for (; p >= 0; p--) { 1022 sb.append(u'0' + getDigitPos(p - scale - exponent)); 1023 } 1024 if (lower < 0) { 1025 sb.append(u'.'); 1026 } 1027 for(; p >= lower; p--) { 1028 sb.append(u'0' + getDigitPos(p - scale - exponent)); 1029 } 1030 return sb; 1031 } 1032 1033 1034 UnicodeString DecimalQuantity::toExponentString() const { 1035 U_ASSERT(!isApproximate); 1036 UnicodeString sb; 1037 if (isNegative()) { 1038 sb.append(u'-'); 1039 } 1040 1041 int32_t upper = scale + precision - 1; 1042 int32_t lower = scale; 1043 if (upper < lReqPos - 1) { 1044 upper = lReqPos - 1; 1045 } 1046 if (lower > rReqPos) { 1047 lower = rReqPos; 1048 } 1049 int32_t p = upper; 1050 if (p < 0) { 1051 sb.append(u'0'); 1052 } 1053 for (; p >= 0; p--) { 1054 sb.append(u'0' + getDigitPos(p - scale)); 1055 } 1056 if (lower < 0) { 1057 sb.append(u'.'); 1058 } 1059 for(; p >= lower; p--) { 1060 sb.append(u'0' + getDigitPos(p - scale)); 1061 } 1062 1063 if (exponent != 0) { 1064 sb.append(u'c'); 1065 ICU_Utility::appendNumber(sb, exponent); 1066 } 1067 1068 return sb; 1069 } 1070 1071 UnicodeString DecimalQuantity::toScientificString() const { 1072 U_ASSERT(!isApproximate); 1073 UnicodeString result; 1074 if (isNegative()) { 1075 result.append(u'-'); 1076 } 1077 if (precision == 0) { 1078 result.append(u"0E+0", -1); 1079 return result; 1080 } 1081 int32_t upperPos = precision - 1; 1082 int32_t lowerPos = 0; 1083 int32_t p = upperPos; 1084 result.append(u'0' + getDigitPos(p)); 1085 if ((--p) >= lowerPos) { 1086 result.append(u'.'); 1087 for (; p >= lowerPos; p--) { 1088 result.append(u'0' + getDigitPos(p)); 1089 } 1090 } 1091 result.append(u'E'); 1092 int32_t _scale = upperPos + scale + exponent; 1093 if (_scale == INT32_MIN) { 1094 result.append(u"-2147483648"); 1095 return result; 1096 } else if (_scale < 0) { 1097 _scale *= -1; 1098 result.append(u'-'); 1099 } else { 1100 result.append(u'+'); 1101 } 1102 if (_scale == 0) { 1103 result.append(u'0'); 1104 } 1105 int32_t insertIndex = result.length(); 1106 while (_scale > 0) { 1107 std::div_t res = std::div(_scale, 10); 1108 result.insert(insertIndex, u'0' + res.rem); 1109 _scale = res.quot; 1110 } 1111 return result; 1112 } 1113 1114 //////////////////////////////////////////////////// 1115 /// End of DecimalQuantity_AbstractBCD.java /// 1116 /// Start of DecimalQuantity_DualStorageBCD.java /// 1117 //////////////////////////////////////////////////// 1118 1119 int8_t DecimalQuantity::getDigitPos(int32_t position) const { 1120 if (usingBytes) { 1121 if (position < 0 || position >= precision) { return 0; } 1122 return fBCD.bcdBytes.ptr[position]; 1123 } else { 1124 if (position < 0 || position >= 16) { return 0; } 1125 return static_cast<int8_t>((fBCD.bcdLong >> (position * 4)) & 0xf); 1126 } 1127 } 1128 1129 void DecimalQuantity::setDigitPos(int32_t position, int8_t value) { 1130 U_ASSERT(position >= 0); 1131 if (usingBytes) { 1132 ensureCapacity(position + 1); 1133 fBCD.bcdBytes.ptr[position] = value; 1134 } else if (position >= 16) { 1135 switchStorage(); 1136 ensureCapacity(position + 1); 1137 fBCD.bcdBytes.ptr[position] = value; 1138 } else { 1139 int shift = position * 4; 1140 fBCD.bcdLong = (fBCD.bcdLong & ~(0xfL << shift)) | (static_cast<long>(value) << shift); 1141 } 1142 } 1143 1144 void DecimalQuantity::shiftLeft(int32_t numDigits) { 1145 if (!usingBytes && precision + numDigits >= 16) { 1146 switchStorage(); 1147 } 1148 if (usingBytes) { 1149 ensureCapacity(precision + numDigits); 1150 uprv_memmove(fBCD.bcdBytes.ptr + numDigits, fBCD.bcdBytes.ptr, precision); 1151 uprv_memset(fBCD.bcdBytes.ptr, 0, numDigits); 1152 } else { 1153 fBCD.bcdLong <<= (numDigits * 4); 1154 } 1155 scale -= numDigits; 1156 precision += numDigits; 1157 } 1158 1159 void DecimalQuantity::shiftRight(int32_t numDigits) { 1160 if (usingBytes) { 1161 int i = 0; 1162 for (; i < precision - numDigits; i++) { 1163 fBCD.bcdBytes.ptr[i] = fBCD.bcdBytes.ptr[i + numDigits]; 1164 } 1165 for (; i < precision; i++) { 1166 fBCD.bcdBytes.ptr[i] = 0; 1167 } 1168 } else { 1169 fBCD.bcdLong >>= (numDigits * 4); 1170 } 1171 scale += numDigits; 1172 precision -= numDigits; 1173 } 1174 1175 void DecimalQuantity::popFromLeft(int32_t numDigits) { 1176 U_ASSERT(numDigits <= precision); 1177 if (usingBytes) { 1178 int i = precision - 1; 1179 for (; i >= precision - numDigits; i--) { 1180 fBCD.bcdBytes.ptr[i] = 0; 1181 } 1182 } else { 1183 fBCD.bcdLong &= (static_cast<uint64_t>(1) << ((precision - numDigits) * 4)) - 1; 1184 } 1185 precision -= numDigits; 1186 } 1187 1188 void DecimalQuantity::setBcdToZero() { 1189 if (usingBytes) { 1190 uprv_free(fBCD.bcdBytes.ptr); 1191 fBCD.bcdBytes.ptr = nullptr; 1192 usingBytes = false; 1193 } 1194 fBCD.bcdLong = 0L; 1195 scale = 0; 1196 precision = 0; 1197 isApproximate = false; 1198 origDouble = 0; 1199 origDelta = 0; 1200 exponent = 0; 1201 } 1202 1203 void DecimalQuantity::readIntToBcd(int32_t n) { 1204 U_ASSERT(n != 0); 1205 // ints always fit inside the long implementation. 1206 uint64_t result = 0L; 1207 int i = 16; 1208 for (; n != 0; n /= 10, i--) { 1209 result = (result >> 4) + ((static_cast<uint64_t>(n) % 10) << 60); 1210 } 1211 U_ASSERT(!usingBytes); 1212 fBCD.bcdLong = result >> (i * 4); 1213 scale = 0; 1214 precision = 16 - i; 1215 } 1216 1217 void DecimalQuantity::readLongToBcd(int64_t n) { 1218 U_ASSERT(n != 0); 1219 if (n >= 10000000000000000L) { 1220 ensureCapacity(); 1221 int i = 0; 1222 for (; n != 0L; n /= 10L, i++) { 1223 fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(n % 10); 1224 } 1225 U_ASSERT(usingBytes); 1226 scale = 0; 1227 precision = i; 1228 } else { 1229 uint64_t result = 0L; 1230 int i = 16; 1231 for (; n != 0L; n /= 10L, i--) { 1232 result = (result >> 4) + ((n % 10) << 60); 1233 } 1234 U_ASSERT(i >= 0); 1235 U_ASSERT(!usingBytes); 1236 fBCD.bcdLong = result >> (i * 4); 1237 scale = 0; 1238 precision = 16 - i; 1239 } 1240 } 1241 1242 void DecimalQuantity::readDecNumberToBcd(const DecNum& decnum) { 1243 const decNumber* dn = decnum.getRawDecNumber(); 1244 if (dn->digits > 16) { 1245 ensureCapacity(dn->digits); 1246 for (int32_t i = 0; i < dn->digits; i++) { 1247 fBCD.bcdBytes.ptr[i] = dn->lsu[i]; 1248 } 1249 } else { 1250 uint64_t result = 0L; 1251 for (int32_t i = 0; i < dn->digits; i++) { 1252 result |= static_cast<uint64_t>(dn->lsu[i]) << (4 * i); 1253 } 1254 fBCD.bcdLong = result; 1255 } 1256 scale = dn->exponent; 1257 precision = dn->digits; 1258 } 1259 1260 void DecimalQuantity::readDoubleConversionToBcd( 1261 const char* buffer, int32_t length, int32_t point) { 1262 // NOTE: Despite the fact that double-conversion's API is called 1263 // "DoubleToAscii", they actually use '0' (as opposed to u8'0'). 1264 if (length > 16) { 1265 ensureCapacity(length); 1266 for (int32_t i = 0; i < length; i++) { 1267 fBCD.bcdBytes.ptr[i] = buffer[length-i-1] - '0'; 1268 } 1269 } else { 1270 uint64_t result = 0L; 1271 for (int32_t i = 0; i < length; i++) { 1272 result |= static_cast<uint64_t>(buffer[length-i-1] - '0') << (4 * i); 1273 } 1274 fBCD.bcdLong = result; 1275 } 1276 scale = point - length; 1277 precision = length; 1278 } 1279 1280 void DecimalQuantity::compact() { 1281 if (usingBytes) { 1282 int32_t delta = 0; 1283 for (; delta < precision && fBCD.bcdBytes.ptr[delta] == 0; delta++); 1284 if (delta == precision) { 1285 // Number is zero 1286 setBcdToZero(); 1287 return; 1288 } else { 1289 // Remove trailing zeros 1290 shiftRight(delta); 1291 } 1292 1293 // Compute precision 1294 int32_t leading = precision - 1; 1295 for (; leading >= 0 && fBCD.bcdBytes.ptr[leading] == 0; leading--); 1296 precision = leading + 1; 1297 1298 // Switch storage mechanism if possible 1299 if (precision <= 16) { 1300 switchStorage(); 1301 } 1302 1303 } else { 1304 if (fBCD.bcdLong == 0L) { 1305 // Number is zero 1306 setBcdToZero(); 1307 return; 1308 } 1309 1310 // Compact the number (remove trailing zeros) 1311 // TODO: Use a more efficient algorithm here and below. There is a logarithmic one. 1312 int32_t delta = 0; 1313 for (; delta < precision && getDigitPos(delta) == 0; delta++); 1314 fBCD.bcdLong >>= delta * 4; 1315 scale += delta; 1316 1317 // Compute precision 1318 int32_t leading = precision - 1; 1319 for (; leading >= 0 && getDigitPos(leading) == 0; leading--); 1320 precision = leading + 1; 1321 } 1322 } 1323 1324 void DecimalQuantity::ensureCapacity() { 1325 ensureCapacity(40); 1326 } 1327 1328 void DecimalQuantity::ensureCapacity(int32_t capacity) { 1329 if (capacity == 0) { return; } 1330 int32_t oldCapacity = usingBytes ? fBCD.bcdBytes.len : 0; 1331 if (!usingBytes) { 1332 // TODO: There is nothing being done to check for memory allocation failures. 1333 // TODO: Consider indexing by nybbles instead of bytes in C++, so that we can 1334 // make these arrays half the size. 1335 fBCD.bcdBytes.ptr = static_cast<int8_t*>(uprv_malloc(capacity * sizeof(int8_t))); 1336 fBCD.bcdBytes.len = capacity; 1337 // Initialize the byte array to zeros (this is done automatically in Java) 1338 uprv_memset(fBCD.bcdBytes.ptr, 0, capacity * sizeof(int8_t)); 1339 } else if (oldCapacity < capacity) { 1340 auto* bcd1 = static_cast<int8_t*>(uprv_malloc(capacity * 2 * sizeof(int8_t))); 1341 uprv_memcpy(bcd1, fBCD.bcdBytes.ptr, oldCapacity * sizeof(int8_t)); 1342 // Initialize the rest of the byte array to zeros (this is done automatically in Java) 1343 uprv_memset(bcd1 + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t)); 1344 uprv_free(fBCD.bcdBytes.ptr); 1345 fBCD.bcdBytes.ptr = bcd1; 1346 fBCD.bcdBytes.len = capacity * 2; 1347 } 1348 usingBytes = true; 1349 } 1350 1351 void DecimalQuantity::switchStorage() { 1352 if (usingBytes) { 1353 // Change from bytes to long 1354 uint64_t bcdLong = 0L; 1355 for (int i = precision - 1; i >= 0; i--) { 1356 bcdLong <<= 4; 1357 bcdLong |= fBCD.bcdBytes.ptr[i]; 1358 } 1359 uprv_free(fBCD.bcdBytes.ptr); 1360 fBCD.bcdBytes.ptr = nullptr; 1361 fBCD.bcdLong = bcdLong; 1362 usingBytes = false; 1363 } else { 1364 // Change from long to bytes 1365 // Copy the long into a local variable since it will get munged when we allocate the bytes 1366 uint64_t bcdLong = fBCD.bcdLong; 1367 ensureCapacity(); 1368 for (int i = 0; i < precision; i++) { 1369 fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(bcdLong & 0xf); 1370 bcdLong >>= 4; 1371 } 1372 U_ASSERT(usingBytes); 1373 } 1374 } 1375 1376 void DecimalQuantity::copyBcdFrom(const DecimalQuantity &other) { 1377 setBcdToZero(); 1378 if (other.usingBytes) { 1379 ensureCapacity(other.precision); 1380 uprv_memcpy(fBCD.bcdBytes.ptr, other.fBCD.bcdBytes.ptr, other.precision * sizeof(int8_t)); 1381 } else { 1382 fBCD.bcdLong = other.fBCD.bcdLong; 1383 } 1384 } 1385 1386 void DecimalQuantity::moveBcdFrom(DecimalQuantity &other) { 1387 setBcdToZero(); 1388 if (other.usingBytes) { 1389 usingBytes = true; 1390 fBCD.bcdBytes.ptr = other.fBCD.bcdBytes.ptr; 1391 fBCD.bcdBytes.len = other.fBCD.bcdBytes.len; 1392 // Take ownership away from the old instance: 1393 other.fBCD.bcdBytes.ptr = nullptr; 1394 other.usingBytes = false; 1395 } else { 1396 fBCD.bcdLong = other.fBCD.bcdLong; 1397 } 1398 } 1399 1400 const char16_t* DecimalQuantity::checkHealth() const { 1401 if (usingBytes) { 1402 if (precision == 0) { return u"Zero precision but we are in byte mode"; } 1403 int32_t capacity = fBCD.bcdBytes.len; 1404 if (precision > capacity) { return u"Precision exceeds length of byte array"; } 1405 if (getDigitPos(precision - 1) == 0) { return u"Most significant digit is zero in byte mode"; } 1406 if (getDigitPos(0) == 0) { return u"Least significant digit is zero in long mode"; } 1407 for (int i = 0; i < precision; i++) { 1408 if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in byte array"; } 1409 if (getDigitPos(i) < 0) { return u"Digit below 0 in byte array"; } 1410 } 1411 for (int i = precision; i < capacity; i++) { 1412 if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in byte array"; } 1413 } 1414 } else { 1415 if (precision == 0 && fBCD.bcdLong != 0) { 1416 return u"Value in bcdLong even though precision is zero"; 1417 } 1418 if (precision > 16) { return u"Precision exceeds length of long"; } 1419 if (precision != 0 && getDigitPos(precision - 1) == 0) { 1420 return u"Most significant digit is zero in long mode"; 1421 } 1422 if (precision != 0 && getDigitPos(0) == 0) { 1423 return u"Least significant digit is zero in long mode"; 1424 } 1425 for (int i = 0; i < precision; i++) { 1426 if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in long"; } 1427 if (getDigitPos(i) < 0) { return u"Digit below 0 in long (?!)"; } 1428 } 1429 for (int i = precision; i < 16; i++) { 1430 if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in long"; } 1431 } 1432 } 1433 1434 // No error 1435 return nullptr; 1436 } 1437 1438 bool DecimalQuantity::operator==(const DecimalQuantity& other) const { 1439 bool basicEquals = 1440 scale == other.scale 1441 && precision == other.precision 1442 && flags == other.flags 1443 && lReqPos == other.lReqPos 1444 && rReqPos == other.rReqPos 1445 && isApproximate == other.isApproximate; 1446 if (!basicEquals) { 1447 return false; 1448 } 1449 1450 if (precision == 0) { 1451 return true; 1452 } else if (isApproximate) { 1453 return origDouble == other.origDouble && origDelta == other.origDelta; 1454 } else { 1455 for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) { 1456 if (getDigit(m) != other.getDigit(m)) { 1457 return false; 1458 } 1459 } 1460 return true; 1461 } 1462 } 1463 1464 UnicodeString DecimalQuantity::toString() const { 1465 UErrorCode localStatus = U_ZERO_ERROR; 1466 MaybeStackArray<char, 30> digits(precision + 1, localStatus); 1467 if (U_FAILURE(localStatus)) { 1468 return ICU_Utility::makeBogusString(); 1469 } 1470 for (int32_t i = 0; i < precision; i++) { 1471 digits[i] = getDigitPos(precision - i - 1) + '0'; 1472 } 1473 digits[precision] = 0; // terminate buffer 1474 char buffer8[100]; 1475 snprintf( 1476 buffer8, 1477 sizeof(buffer8), 1478 "<DecimalQuantity %d:%d %s %s%s%s%d>", 1479 lReqPos, 1480 rReqPos, 1481 (usingBytes ? "bytes" : "long"), 1482 (isNegative() ? "-" : ""), 1483 (precision == 0 ? "0" : digits.getAlias()), 1484 "E", 1485 scale); 1486 return UnicodeString(buffer8, -1, US_INV); 1487 } 1488 1489 #endif /* #if !UCONFIG_NO_FORMATTING */