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