• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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