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