• 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
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 
24 using namespace icu;
25 using namespace icu::number;
26 using namespace icu::number::impl;
27 
28 using icu::double_conversion::DoubleToStringConverter;
29 using icu::double_conversion::StringToDoubleConverter;
30 
31 namespace {
32 
33 int8_t NEGATIVE_FLAG = 1;
34 int8_t INFINITY_FLAG = 2;
35 int8_t NAN_FLAG = 4;
36 
37 /** Helper function for safe subtraction (no overflow). */
safeSubtract(int32_t a,int32_t b)38 inline int32_t safeSubtract(int32_t a, int32_t b) {
39     // Note: In C++, signed integer subtraction is undefined behavior.
40     int32_t diff = static_cast<int32_t>(static_cast<uint32_t>(a) - static_cast<uint32_t>(b));
41     if (b < 0 && diff < a) { return INT32_MAX; }
42     if (b > 0 && diff > a) { return INT32_MIN; }
43     return diff;
44 }
45 
46 static double DOUBLE_MULTIPLIERS[] = {
47         1e0,
48         1e1,
49         1e2,
50         1e3,
51         1e4,
52         1e5,
53         1e6,
54         1e7,
55         1e8,
56         1e9,
57         1e10,
58         1e11,
59         1e12,
60         1e13,
61         1e14,
62         1e15,
63         1e16,
64         1e17,
65         1e18,
66         1e19,
67         1e20,
68         1e21};
69 
70 }  // namespace
71 
72 icu::IFixedDecimal::~IFixedDecimal() = default;
73 
DecimalQuantity()74 DecimalQuantity::DecimalQuantity() {
75     setBcdToZero();
76     flags = 0;
77 }
78 
~DecimalQuantity()79 DecimalQuantity::~DecimalQuantity() {
80     if (usingBytes) {
81         uprv_free(fBCD.bcdBytes.ptr);
82         fBCD.bcdBytes.ptr = nullptr;
83         usingBytes = false;
84     }
85 }
86 
DecimalQuantity(const DecimalQuantity & other)87 DecimalQuantity::DecimalQuantity(const DecimalQuantity &other) {
88     *this = other;
89 }
90 
DecimalQuantity(DecimalQuantity && src)91 DecimalQuantity::DecimalQuantity(DecimalQuantity&& src) U_NOEXCEPT {
92     *this = std::move(src);
93 }
94 
operator =(const DecimalQuantity & other)95 DecimalQuantity &DecimalQuantity::operator=(const DecimalQuantity &other) {
96     if (this == &other) {
97         return *this;
98     }
99     copyBcdFrom(other);
100     copyFieldsFrom(other);
101     return *this;
102 }
103 
operator =(DecimalQuantity && src)104 DecimalQuantity& DecimalQuantity::operator=(DecimalQuantity&& src) U_NOEXCEPT {
105     if (this == &src) {
106         return *this;
107     }
108     moveBcdFrom(src);
109     copyFieldsFrom(src);
110     return *this;
111 }
112 
copyFieldsFrom(const DecimalQuantity & other)113 void DecimalQuantity::copyFieldsFrom(const DecimalQuantity& other) {
114     bogus = other.bogus;
115     lOptPos = other.lOptPos;
116     lReqPos = other.lReqPos;
117     rReqPos = other.rReqPos;
118     rOptPos = other.rOptPos;
119     scale = other.scale;
120     precision = other.precision;
121     flags = other.flags;
122     origDouble = other.origDouble;
123     origDelta = other.origDelta;
124     isApproximate = other.isApproximate;
125 }
126 
clear()127 void DecimalQuantity::clear() {
128     lOptPos = INT32_MAX;
129     lReqPos = 0;
130     rReqPos = 0;
131     rOptPos = INT32_MIN;
132     flags = 0;
133     setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data
134 }
135 
setIntegerLength(int32_t minInt,int32_t maxInt)136 void DecimalQuantity::setIntegerLength(int32_t minInt, int32_t maxInt) {
137     // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
138     U_ASSERT(minInt >= 0);
139     U_ASSERT(maxInt >= minInt);
140 
141     // Special behavior: do not set minInt to be less than what is already set.
142     // This is so significant digits rounding can set the integer length.
143     if (minInt < lReqPos) {
144         minInt = lReqPos;
145     }
146 
147     // Save values into internal state
148     // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
149     lOptPos = maxInt;
150     lReqPos = minInt;
151 }
152 
setFractionLength(int32_t minFrac,int32_t maxFrac)153 void DecimalQuantity::setFractionLength(int32_t minFrac, int32_t maxFrac) {
154     // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
155     U_ASSERT(minFrac >= 0);
156     U_ASSERT(maxFrac >= minFrac);
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     rOptPos = -maxFrac;
162 }
163 
getPositionFingerprint() const164 uint64_t DecimalQuantity::getPositionFingerprint() const {
165     uint64_t fingerprint = 0;
166     fingerprint ^= lOptPos;
167     fingerprint ^= (lReqPos << 16);
168     fingerprint ^= (static_cast<uint64_t>(rReqPos) << 32);
169     fingerprint ^= (static_cast<uint64_t>(rOptPos) << 48);
170     return fingerprint;
171 }
172 
roundToIncrement(double roundingIncrement,RoundingMode roundingMode,int32_t maxFrac,UErrorCode & status)173 void DecimalQuantity::roundToIncrement(double roundingIncrement, RoundingMode roundingMode,
174                                        int32_t maxFrac, UErrorCode& status) {
175     // TODO(13701): This is innefficient.  Improve?
176     // TODO(13701): Should we convert to decNumber instead?
177     roundToInfinity();
178     double temp = toDouble();
179     temp /= roundingIncrement;
180     // Use another DecimalQuantity to perform the actual rounding...
181     DecimalQuantity dq;
182     dq.setToDouble(temp);
183     dq.roundToMagnitude(0, roundingMode, status);
184     temp = dq.toDouble();
185     temp *= roundingIncrement;
186     setToDouble(temp);
187     // Since we reset the value to a double, we need to specify the rounding boundary
188     // in order to get the DecimalQuantity out of approximation mode.
189     // NOTE: In Java, we have minMaxFrac, but in C++, the two are differentiated.
190     roundToMagnitude(-maxFrac, roundingMode, status);
191 }
192 
multiplyBy(const DecNum & multiplicand,UErrorCode & status)193 void DecimalQuantity::multiplyBy(const DecNum& multiplicand, UErrorCode& status) {
194     if (isInfinite() || isZero() || isNaN()) {
195         return;
196     }
197     // Convert to DecNum, multiply, and convert back.
198     DecNum decnum;
199     toDecNum(decnum, status);
200     if (U_FAILURE(status)) { return; }
201     decnum.multiplyBy(multiplicand, status);
202     if (U_FAILURE(status)) { return; }
203     setToDecNum(decnum, status);
204 }
205 
divideBy(const DecNum & divisor,UErrorCode & status)206 void DecimalQuantity::divideBy(const DecNum& divisor, UErrorCode& status) {
207     if (isInfinite() || isZero() || isNaN()) {
208         return;
209     }
210     // Convert to DecNum, multiply, and convert back.
211     DecNum decnum;
212     toDecNum(decnum, status);
213     if (U_FAILURE(status)) { return; }
214     decnum.divideBy(divisor, status);
215     if (U_FAILURE(status)) { return; }
216     setToDecNum(decnum, status);
217 }
218 
negate()219 void DecimalQuantity::negate() {
220     flags ^= NEGATIVE_FLAG;
221 }
222 
getMagnitude() const223 int32_t DecimalQuantity::getMagnitude() const {
224     U_ASSERT(precision != 0);
225     return scale + precision - 1;
226 }
227 
adjustMagnitude(int32_t delta)228 bool DecimalQuantity::adjustMagnitude(int32_t delta) {
229     if (precision != 0) {
230         // i.e., scale += delta; origDelta += delta
231         bool overflow = uprv_add32_overflow(scale, delta, &scale);
232         overflow = uprv_add32_overflow(origDelta, delta, &origDelta) || overflow;
233         // Make sure that precision + scale won't overflow, either
234         int32_t dummy;
235         overflow = overflow || uprv_add32_overflow(scale, precision, &dummy);
236         return overflow;
237     }
238     return false;
239 }
240 
getPluralOperand(PluralOperand operand) const241 double DecimalQuantity::getPluralOperand(PluralOperand operand) const {
242     // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
243     // See the comment at the top of this file explaining the "isApproximate" field.
244     U_ASSERT(!isApproximate);
245 
246     switch (operand) {
247         case PLURAL_OPERAND_I:
248             // Invert the negative sign if necessary
249             return static_cast<double>(isNegative() ? -toLong(true) : toLong(true));
250         case PLURAL_OPERAND_F:
251             return static_cast<double>(toFractionLong(true));
252         case PLURAL_OPERAND_T:
253             return static_cast<double>(toFractionLong(false));
254         case PLURAL_OPERAND_V:
255             return fractionCount();
256         case PLURAL_OPERAND_W:
257             return fractionCountWithoutTrailingZeros();
258         default:
259             return std::abs(toDouble());
260     }
261 }
262 
hasIntegerValue() const263 bool DecimalQuantity::hasIntegerValue() const {
264     return scale >= 0;
265 }
266 
getUpperDisplayMagnitude() const267 int32_t DecimalQuantity::getUpperDisplayMagnitude() const {
268     // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
269     // See the comment in the header file explaining the "isApproximate" field.
270     U_ASSERT(!isApproximate);
271 
272     int32_t magnitude = scale + precision;
273     int32_t result = (lReqPos > magnitude) ? lReqPos : (lOptPos < magnitude) ? lOptPos : magnitude;
274     return result - 1;
275 }
276 
getLowerDisplayMagnitude() const277 int32_t DecimalQuantity::getLowerDisplayMagnitude() const {
278     // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
279     // See the comment in the header file explaining the "isApproximate" field.
280     U_ASSERT(!isApproximate);
281 
282     int32_t magnitude = scale;
283     int32_t result = (rReqPos < magnitude) ? rReqPos : (rOptPos > magnitude) ? rOptPos : magnitude;
284     return result;
285 }
286 
getDigit(int32_t magnitude) const287 int8_t DecimalQuantity::getDigit(int32_t magnitude) const {
288     // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
289     // See the comment at the top of this file explaining the "isApproximate" field.
290     U_ASSERT(!isApproximate);
291 
292     return getDigitPos(magnitude - scale);
293 }
294 
fractionCount() const295 int32_t DecimalQuantity::fractionCount() const {
296     return -getLowerDisplayMagnitude();
297 }
298 
fractionCountWithoutTrailingZeros() const299 int32_t DecimalQuantity::fractionCountWithoutTrailingZeros() const {
300     return -scale > 0 ? -scale : 0;  // max(-scale, 0)
301 }
302 
isNegative() const303 bool DecimalQuantity::isNegative() const {
304     return (flags & NEGATIVE_FLAG) != 0;
305 }
306 
signum() const307 int8_t DecimalQuantity::signum() const {
308     return isNegative() ? -1 : isZero() ? 0 : 1;
309 }
310 
isInfinite() const311 bool DecimalQuantity::isInfinite() const {
312     return (flags & INFINITY_FLAG) != 0;
313 }
314 
isNaN() const315 bool DecimalQuantity::isNaN() const {
316     return (flags & NAN_FLAG) != 0;
317 }
318 
isZero() const319 bool DecimalQuantity::isZero() const {
320     return precision == 0;
321 }
322 
setToInt(int32_t n)323 DecimalQuantity &DecimalQuantity::setToInt(int32_t n) {
324     setBcdToZero();
325     flags = 0;
326     if (n == INT32_MIN) {
327         flags |= NEGATIVE_FLAG;
328         // leave as INT32_MIN; handled below in _setToInt()
329     } else if (n < 0) {
330         flags |= NEGATIVE_FLAG;
331         n = -n;
332     }
333     if (n != 0) {
334         _setToInt(n);
335         compact();
336     }
337     return *this;
338 }
339 
_setToInt(int32_t n)340 void DecimalQuantity::_setToInt(int32_t n) {
341     if (n == INT32_MIN) {
342         readLongToBcd(-static_cast<int64_t>(n));
343     } else {
344         readIntToBcd(n);
345     }
346 }
347 
setToLong(int64_t n)348 DecimalQuantity &DecimalQuantity::setToLong(int64_t n) {
349     setBcdToZero();
350     flags = 0;
351     if (n < 0 && n > INT64_MIN) {
352         flags |= NEGATIVE_FLAG;
353         n = -n;
354     }
355     if (n != 0) {
356         _setToLong(n);
357         compact();
358     }
359     return *this;
360 }
361 
_setToLong(int64_t n)362 void DecimalQuantity::_setToLong(int64_t n) {
363     if (n == INT64_MIN) {
364         DecNum decnum;
365         UErrorCode localStatus = U_ZERO_ERROR;
366         decnum.setTo("9.223372036854775808E+18", localStatus);
367         if (U_FAILURE(localStatus)) { return; } // unexpected
368         flags |= NEGATIVE_FLAG;
369         readDecNumberToBcd(decnum);
370     } else if (n <= INT32_MAX) {
371         readIntToBcd(static_cast<int32_t>(n));
372     } else {
373         readLongToBcd(n);
374     }
375 }
376 
setToDouble(double n)377 DecimalQuantity &DecimalQuantity::setToDouble(double n) {
378     setBcdToZero();
379     flags = 0;
380     // signbit() from <math.h> handles +0.0 vs -0.0
381     if (std::signbit(n)) {
382         flags |= NEGATIVE_FLAG;
383         n = -n;
384     }
385     if (std::isnan(n) != 0) {
386         flags |= NAN_FLAG;
387     } else if (std::isfinite(n) == 0) {
388         flags |= INFINITY_FLAG;
389     } else if (n != 0) {
390         _setToDoubleFast(n);
391         compact();
392     }
393     return *this;
394 }
395 
_setToDoubleFast(double n)396 void DecimalQuantity::_setToDoubleFast(double n) {
397     isApproximate = true;
398     origDouble = n;
399     origDelta = 0;
400 
401     // Make sure the double is an IEEE 754 double.  If not, fall back to the slow path right now.
402     // TODO: Make a fast path for other types of doubles.
403     if (!std::numeric_limits<double>::is_iec559) {
404         convertToAccurateDouble();
405         // Turn off the approximate double flag, since the value is now exact.
406         isApproximate = false;
407         origDouble = 0.0;
408         return;
409     }
410 
411     // To get the bits from the double, use memcpy, which takes care of endianness.
412     uint64_t ieeeBits;
413     uprv_memcpy(&ieeeBits, &n, sizeof(n));
414     int32_t exponent = static_cast<int32_t>((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff;
415 
416     // Not all integers can be represented exactly for exponent > 52
417     if (exponent <= 52 && static_cast<int64_t>(n) == n) {
418         _setToLong(static_cast<int64_t>(n));
419         return;
420     }
421 
422     // 3.3219... is log2(10)
423     auto fracLength = static_cast<int32_t> ((52 - exponent) / 3.32192809489);
424     if (fracLength >= 0) {
425         int32_t i = fracLength;
426         // 1e22 is the largest exact double.
427         for (; i >= 22; i -= 22) n *= 1e22;
428         n *= DOUBLE_MULTIPLIERS[i];
429     } else {
430         int32_t i = fracLength;
431         // 1e22 is the largest exact double.
432         for (; i <= -22; i += 22) n /= 1e22;
433         n /= DOUBLE_MULTIPLIERS[-i];
434     }
435     auto result = static_cast<int64_t>(std::round(n));
436     if (result != 0) {
437         _setToLong(result);
438         scale -= fracLength;
439     }
440 }
441 
convertToAccurateDouble()442 void DecimalQuantity::convertToAccurateDouble() {
443     U_ASSERT(origDouble != 0);
444     int32_t delta = origDelta;
445 
446     // Call the slow oracle function (Double.toString in Java, DoubleToAscii in C++).
447     char buffer[DoubleToStringConverter::kBase10MaximalLength + 1];
448     bool sign; // unused; always positive
449     int32_t length;
450     int32_t point;
451     DoubleToStringConverter::DoubleToAscii(
452         origDouble,
453         DoubleToStringConverter::DtoaMode::SHORTEST,
454         0,
455         buffer,
456         sizeof(buffer),
457         &sign,
458         &length,
459         &point
460     );
461 
462     setBcdToZero();
463     readDoubleConversionToBcd(buffer, length, point);
464     scale += delta;
465     explicitExactDouble = true;
466 }
467 
setToDecNumber(StringPiece n,UErrorCode & status)468 DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n, UErrorCode& status) {
469     setBcdToZero();
470     flags = 0;
471 
472     // Compute the decNumber representation
473     DecNum decnum;
474     decnum.setTo(n, status);
475 
476     _setToDecNum(decnum, status);
477     return *this;
478 }
479 
setToDecNum(const DecNum & decnum,UErrorCode & status)480 DecimalQuantity& DecimalQuantity::setToDecNum(const DecNum& decnum, UErrorCode& status) {
481     setBcdToZero();
482     flags = 0;
483 
484     _setToDecNum(decnum, status);
485     return *this;
486 }
487 
_setToDecNum(const DecNum & decnum,UErrorCode & status)488 void DecimalQuantity::_setToDecNum(const DecNum& decnum, UErrorCode& status) {
489     if (U_FAILURE(status)) { return; }
490     if (decnum.isNegative()) {
491         flags |= NEGATIVE_FLAG;
492     }
493     if (!decnum.isZero()) {
494         readDecNumberToBcd(decnum);
495         compact();
496     }
497 }
498 
toLong(bool truncateIfOverflow) const499 int64_t DecimalQuantity::toLong(bool truncateIfOverflow) const {
500     // NOTE: Call sites should be guarded by fitsInLong(), like this:
501     // if (dq.fitsInLong()) { /* use dq.toLong() */ } else { /* use some fallback */ }
502     // Fallback behavior upon truncateIfOverflow is to truncate at 17 digits.
503     uint64_t result = 0L;
504     int32_t upperMagnitude = std::min(scale + precision, lOptPos) - 1;
505     if (truncateIfOverflow) {
506         upperMagnitude = std::min(upperMagnitude, 17);
507     }
508     for (int32_t magnitude = upperMagnitude; magnitude >= 0; magnitude--) {
509         result = result * 10 + getDigitPos(magnitude - scale);
510     }
511     if (isNegative()) {
512         return static_cast<int64_t>(0LL - result); // i.e., -result
513     }
514     return static_cast<int64_t>(result);
515 }
516 
toFractionLong(bool includeTrailingZeros) const517 uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const {
518     uint64_t result = 0L;
519     int32_t magnitude = -1;
520     int32_t lowerMagnitude = std::max(scale, rOptPos);
521     if (includeTrailingZeros) {
522         lowerMagnitude = std::min(lowerMagnitude, rReqPos);
523     }
524     for (; magnitude >= lowerMagnitude && result <= 1e18L; magnitude--) {
525         result = result * 10 + getDigitPos(magnitude - scale);
526     }
527     // Remove trailing zeros; this can happen during integer overflow cases.
528     if (!includeTrailingZeros) {
529         while (result > 0 && (result % 10) == 0) {
530             result /= 10;
531         }
532     }
533     return result;
534 }
535 
fitsInLong(bool ignoreFraction) const536 bool DecimalQuantity::fitsInLong(bool ignoreFraction) const {
537     if (isZero()) {
538         return true;
539     }
540     if (scale < 0 && !ignoreFraction) {
541         return false;
542     }
543     int magnitude = getMagnitude();
544     if (magnitude < 18) {
545         return true;
546     }
547     if (magnitude > 18) {
548         return false;
549     }
550     // Hard case: the magnitude is 10^18.
551     // The largest int64 is: 9,223,372,036,854,775,807
552     for (int p = 0; p < precision; p++) {
553         int8_t digit = getDigit(18 - p);
554         static int8_t INT64_BCD[] = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 };
555         if (digit < INT64_BCD[p]) {
556             return true;
557         } else if (digit > INT64_BCD[p]) {
558             return false;
559         }
560     }
561     // Exactly equal to max long plus one.
562     return isNegative();
563 }
564 
toDouble() const565 double DecimalQuantity::toDouble() const {
566     // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
567     // See the comment in the header file explaining the "isApproximate" field.
568     U_ASSERT(!isApproximate);
569 
570     if (isNaN()) {
571         return NAN;
572     } else if (isInfinite()) {
573         return isNegative() ? -INFINITY : INFINITY;
574     }
575 
576     // We are processing well-formed input, so we don't need any special options to StringToDoubleConverter.
577     StringToDoubleConverter converter(0, 0, 0, "", "");
578     UnicodeString numberString = this->toScientificString();
579     int32_t count;
580     return converter.StringToDouble(
581             reinterpret_cast<const uint16_t*>(numberString.getBuffer()),
582             numberString.length(),
583             &count);
584 }
585 
toDecNum(DecNum & output,UErrorCode & status) const586 void DecimalQuantity::toDecNum(DecNum& output, UErrorCode& status) const {
587     // Special handling for zero
588     if (precision == 0) {
589         output.setTo("0", status);
590     }
591 
592     // Use the BCD constructor. We need to do a little bit of work to convert, though.
593     // The decNumber constructor expects most-significant first, but we store least-significant first.
594     MaybeStackArray<uint8_t, 20> ubcd(precision);
595     for (int32_t m = 0; m < precision; m++) {
596         ubcd[precision - m - 1] = static_cast<uint8_t>(getDigitPos(m));
597     }
598     output.setTo(ubcd.getAlias(), precision, scale, isNegative(), status);
599 }
600 
truncate()601 void DecimalQuantity::truncate() {
602     if (scale < 0) {
603         shiftRight(-scale);
604         scale = 0;
605         compact();
606     }
607 }
608 
roundToMagnitude(int32_t magnitude,RoundingMode roundingMode,UErrorCode & status)609 void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) {
610     // The position in the BCD at which rounding will be performed; digits to the right of position
611     // will be rounded away.
612     // TODO: Andy: There was a test failure because of integer overflow here. Should I do
613     // "safe subtraction" everywhere in the code?  What's the nicest way to do it?
614     int position = safeSubtract(magnitude, scale);
615 
616     if (position <= 0 && !isApproximate) {
617         // All digits are to the left of the rounding magnitude.
618     } else if (precision == 0) {
619         // No rounding for zero.
620     } else {
621         // Perform rounding logic.
622         // "leading" = most significant digit to the right of rounding
623         // "trailing" = least significant digit to the left of rounding
624         int8_t leadingDigit = getDigitPos(safeSubtract(position, 1));
625         int8_t trailingDigit = getDigitPos(position);
626 
627         // Compute which section of the number we are in.
628         // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles)
629         // LOWER means we are between the bottom edge and the midpoint, like 1.391
630         // MIDPOINT means we are exactly in the middle, like 1.500
631         // UPPER means we are between the midpoint and the top edge, like 1.916
632         roundingutils::Section section = roundingutils::SECTION_MIDPOINT;
633         if (!isApproximate) {
634             if (leadingDigit < 5) {
635                 section = roundingutils::SECTION_LOWER;
636             } else if (leadingDigit > 5) {
637                 section = roundingutils::SECTION_UPPER;
638             } else {
639                 for (int p = safeSubtract(position, 2); p >= 0; p--) {
640                     if (getDigitPos(p) != 0) {
641                         section = roundingutils::SECTION_UPPER;
642                         break;
643                     }
644                 }
645             }
646         } else {
647             int32_t p = safeSubtract(position, 2);
648             int32_t minP = uprv_max(0, precision - 14);
649             if (leadingDigit == 0) {
650                 section = roundingutils::SECTION_LOWER_EDGE;
651                 for (; p >= minP; p--) {
652                     if (getDigitPos(p) != 0) {
653                         section = roundingutils::SECTION_LOWER;
654                         break;
655                     }
656                 }
657             } else if (leadingDigit == 4) {
658                 for (; p >= minP; p--) {
659                     if (getDigitPos(p) != 9) {
660                         section = roundingutils::SECTION_LOWER;
661                         break;
662                     }
663                 }
664             } else if (leadingDigit == 5) {
665                 for (; p >= minP; p--) {
666                     if (getDigitPos(p) != 0) {
667                         section = roundingutils::SECTION_UPPER;
668                         break;
669                     }
670                 }
671             } else if (leadingDigit == 9) {
672                 section = roundingutils::SECTION_UPPER_EDGE;
673                 for (; p >= minP; p--) {
674                     if (getDigitPos(p) != 9) {
675                         section = roundingutils::SECTION_UPPER;
676                         break;
677                     }
678                 }
679             } else if (leadingDigit < 5) {
680                 section = roundingutils::SECTION_LOWER;
681             } else {
682                 section = roundingutils::SECTION_UPPER;
683             }
684 
685             bool roundsAtMidpoint = roundingutils::roundsAtMidpoint(roundingMode);
686             if (safeSubtract(position, 1) < precision - 14 ||
687                 (roundsAtMidpoint && section == roundingutils::SECTION_MIDPOINT) ||
688                 (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) {
689                 // Oops! This means that we have to get the exact representation of the double, because
690                 // the zone of uncertainty is along the rounding boundary.
691                 convertToAccurateDouble();
692                 roundToMagnitude(magnitude, roundingMode, status); // start over
693                 return;
694             }
695 
696             // Turn off the approximate double flag, since the value is now confirmed to be exact.
697             isApproximate = false;
698             origDouble = 0.0;
699             origDelta = 0;
700 
701             if (position <= 0) {
702                 // All digits are to the left of the rounding magnitude.
703                 return;
704             }
705 
706             // Good to continue rounding.
707             if (section == -1) { section = roundingutils::SECTION_LOWER; }
708             if (section == -2) { section = roundingutils::SECTION_UPPER; }
709         }
710 
711         bool roundDown = roundingutils::getRoundingDirection((trailingDigit % 2) == 0,
712                 isNegative(),
713                 section,
714                 roundingMode,
715                 status);
716         if (U_FAILURE(status)) {
717             return;
718         }
719 
720         // Perform truncation
721         if (position >= precision) {
722             setBcdToZero();
723             scale = magnitude;
724         } else {
725             shiftRight(position);
726         }
727 
728         // Bubble the result to the higher digits
729         if (!roundDown) {
730             if (trailingDigit == 9) {
731                 int bubblePos = 0;
732                 // Note: in the long implementation, the most digits BCD can have at this point is 15,
733                 // so bubblePos <= 15 and getDigitPos(bubblePos) is safe.
734                 for (; getDigitPos(bubblePos) == 9; bubblePos++) {}
735                 shiftRight(bubblePos); // shift off the trailing 9s
736             }
737             int8_t digit0 = getDigitPos(0);
738             U_ASSERT(digit0 != 9);
739             setDigitPos(0, static_cast<int8_t>(digit0 + 1));
740             precision += 1; // in case an extra digit got added
741         }
742 
743         compact();
744     }
745 }
746 
roundToInfinity()747 void DecimalQuantity::roundToInfinity() {
748     if (isApproximate) {
749         convertToAccurateDouble();
750     }
751 }
752 
appendDigit(int8_t value,int32_t leadingZeros,bool appendAsInteger)753 void DecimalQuantity::appendDigit(int8_t value, int32_t leadingZeros, bool appendAsInteger) {
754     U_ASSERT(leadingZeros >= 0);
755 
756     // Zero requires special handling to maintain the invariant that the least-significant digit
757     // in the BCD is nonzero.
758     if (value == 0) {
759         if (appendAsInteger && precision != 0) {
760             scale += leadingZeros + 1;
761         }
762         return;
763     }
764 
765     // Deal with trailing zeros
766     if (scale > 0) {
767         leadingZeros += scale;
768         if (appendAsInteger) {
769             scale = 0;
770         }
771     }
772 
773     // Append digit
774     shiftLeft(leadingZeros + 1);
775     setDigitPos(0, value);
776 
777     // Fix scale if in integer mode
778     if (appendAsInteger) {
779         scale += leadingZeros + 1;
780     }
781 }
782 
toPlainString() const783 UnicodeString DecimalQuantity::toPlainString() const {
784     U_ASSERT(!isApproximate);
785     UnicodeString sb;
786     if (isNegative()) {
787         sb.append(u'-');
788     }
789     if (precision == 0 || getMagnitude() < 0) {
790         sb.append(u'0');
791     }
792     for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
793         if (m == -1) { sb.append(u'.'); }
794         sb.append(getDigit(m) + u'0');
795     }
796     return sb;
797 }
798 
toScientificString() const799 UnicodeString DecimalQuantity::toScientificString() const {
800     U_ASSERT(!isApproximate);
801     UnicodeString result;
802     if (isNegative()) {
803         result.append(u'-');
804     }
805     if (precision == 0) {
806         result.append(u"0E+0", -1);
807         return result;
808     }
809     // NOTE: It is not safe to add to lOptPos (aka maxInt) or subtract from
810     // rOptPos (aka -maxFrac) due to overflow.
811     int32_t upperPos = std::min(precision + scale, lOptPos) - scale - 1;
812     int32_t lowerPos = std::max(scale, rOptPos) - scale;
813     int32_t p = upperPos;
814     result.append(u'0' + getDigitPos(p));
815     if ((--p) >= lowerPos) {
816         result.append(u'.');
817         for (; p >= lowerPos; p--) {
818             result.append(u'0' + getDigitPos(p));
819         }
820     }
821     result.append(u'E');
822     int32_t _scale = upperPos + scale;
823     if (_scale == INT32_MIN) {
824         result.append({u"-2147483648", -1});
825         return result;
826     } else if (_scale < 0) {
827         _scale *= -1;
828         result.append(u'-');
829     } else {
830         result.append(u'+');
831     }
832     if (_scale == 0) {
833         result.append(u'0');
834     }
835     int32_t insertIndex = result.length();
836     while (_scale > 0) {
837         std::div_t res = std::div(_scale, 10);
838         result.insert(insertIndex, u'0' + res.rem);
839         _scale = res.quot;
840     }
841     return result;
842 }
843 
844 ////////////////////////////////////////////////////
845 /// End of DecimalQuantity_AbstractBCD.java      ///
846 /// Start of DecimalQuantity_DualStorageBCD.java ///
847 ////////////////////////////////////////////////////
848 
getDigitPos(int32_t position) const849 int8_t DecimalQuantity::getDigitPos(int32_t position) const {
850     if (usingBytes) {
851         if (position < 0 || position >= precision) { return 0; }
852         return fBCD.bcdBytes.ptr[position];
853     } else {
854         if (position < 0 || position >= 16) { return 0; }
855         return (int8_t) ((fBCD.bcdLong >> (position * 4)) & 0xf);
856     }
857 }
858 
setDigitPos(int32_t position,int8_t value)859 void DecimalQuantity::setDigitPos(int32_t position, int8_t value) {
860     U_ASSERT(position >= 0);
861     if (usingBytes) {
862         ensureCapacity(position + 1);
863         fBCD.bcdBytes.ptr[position] = value;
864     } else if (position >= 16) {
865         switchStorage();
866         ensureCapacity(position + 1);
867         fBCD.bcdBytes.ptr[position] = value;
868     } else {
869         int shift = position * 4;
870         fBCD.bcdLong = (fBCD.bcdLong & ~(0xfL << shift)) | ((long) value << shift);
871     }
872 }
873 
shiftLeft(int32_t numDigits)874 void DecimalQuantity::shiftLeft(int32_t numDigits) {
875     if (!usingBytes && precision + numDigits > 16) {
876         switchStorage();
877     }
878     if (usingBytes) {
879         ensureCapacity(precision + numDigits);
880         int i = precision + numDigits - 1;
881         for (; i >= numDigits; i--) {
882             fBCD.bcdBytes.ptr[i] = fBCD.bcdBytes.ptr[i - numDigits];
883         }
884         for (; i >= 0; i--) {
885             fBCD.bcdBytes.ptr[i] = 0;
886         }
887     } else {
888         fBCD.bcdLong <<= (numDigits * 4);
889     }
890     scale -= numDigits;
891     precision += numDigits;
892 }
893 
shiftRight(int32_t numDigits)894 void DecimalQuantity::shiftRight(int32_t numDigits) {
895     if (usingBytes) {
896         int i = 0;
897         for (; i < precision - numDigits; i++) {
898             fBCD.bcdBytes.ptr[i] = fBCD.bcdBytes.ptr[i + numDigits];
899         }
900         for (; i < precision; i++) {
901             fBCD.bcdBytes.ptr[i] = 0;
902         }
903     } else {
904         fBCD.bcdLong >>= (numDigits * 4);
905     }
906     scale += numDigits;
907     precision -= numDigits;
908 }
909 
setBcdToZero()910 void DecimalQuantity::setBcdToZero() {
911     if (usingBytes) {
912         uprv_free(fBCD.bcdBytes.ptr);
913         fBCD.bcdBytes.ptr = nullptr;
914         usingBytes = false;
915     }
916     fBCD.bcdLong = 0L;
917     scale = 0;
918     precision = 0;
919     isApproximate = false;
920     origDouble = 0;
921     origDelta = 0;
922 }
923 
readIntToBcd(int32_t n)924 void DecimalQuantity::readIntToBcd(int32_t n) {
925     U_ASSERT(n != 0);
926     // ints always fit inside the long implementation.
927     uint64_t result = 0L;
928     int i = 16;
929     for (; n != 0; n /= 10, i--) {
930         result = (result >> 4) + ((static_cast<uint64_t>(n) % 10) << 60);
931     }
932     U_ASSERT(!usingBytes);
933     fBCD.bcdLong = result >> (i * 4);
934     scale = 0;
935     precision = 16 - i;
936 }
937 
readLongToBcd(int64_t n)938 void DecimalQuantity::readLongToBcd(int64_t n) {
939     U_ASSERT(n != 0);
940     if (n >= 10000000000000000L) {
941         ensureCapacity();
942         int i = 0;
943         for (; n != 0L; n /= 10L, i++) {
944             fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(n % 10);
945         }
946         U_ASSERT(usingBytes);
947         scale = 0;
948         precision = i;
949     } else {
950         uint64_t result = 0L;
951         int i = 16;
952         for (; n != 0L; n /= 10L, i--) {
953             result = (result >> 4) + ((n % 10) << 60);
954         }
955         U_ASSERT(i >= 0);
956         U_ASSERT(!usingBytes);
957         fBCD.bcdLong = result >> (i * 4);
958         scale = 0;
959         precision = 16 - i;
960     }
961 }
962 
readDecNumberToBcd(const DecNum & decnum)963 void DecimalQuantity::readDecNumberToBcd(const DecNum& decnum) {
964     const decNumber* dn = decnum.getRawDecNumber();
965     if (dn->digits > 16) {
966         ensureCapacity(dn->digits);
967         for (int32_t i = 0; i < dn->digits; i++) {
968             fBCD.bcdBytes.ptr[i] = dn->lsu[i];
969         }
970     } else {
971         uint64_t result = 0L;
972         for (int32_t i = 0; i < dn->digits; i++) {
973             result |= static_cast<uint64_t>(dn->lsu[i]) << (4 * i);
974         }
975         fBCD.bcdLong = result;
976     }
977     scale = dn->exponent;
978     precision = dn->digits;
979 }
980 
readDoubleConversionToBcd(const char * buffer,int32_t length,int32_t point)981 void DecimalQuantity::readDoubleConversionToBcd(
982         const char* buffer, int32_t length, int32_t point) {
983     // NOTE: Despite the fact that double-conversion's API is called
984     // "DoubleToAscii", they actually use '0' (as opposed to u8'0').
985     if (length > 16) {
986         ensureCapacity(length);
987         for (int32_t i = 0; i < length; i++) {
988             fBCD.bcdBytes.ptr[i] = buffer[length-i-1] - '0';
989         }
990     } else {
991         uint64_t result = 0L;
992         for (int32_t i = 0; i < length; i++) {
993             result |= static_cast<uint64_t>(buffer[length-i-1] - '0') << (4 * i);
994         }
995         fBCD.bcdLong = result;
996     }
997     scale = point - length;
998     precision = length;
999 }
1000 
compact()1001 void DecimalQuantity::compact() {
1002     if (usingBytes) {
1003         int32_t delta = 0;
1004         for (; delta < precision && fBCD.bcdBytes.ptr[delta] == 0; delta++);
1005         if (delta == precision) {
1006             // Number is zero
1007             setBcdToZero();
1008             return;
1009         } else {
1010             // Remove trailing zeros
1011             shiftRight(delta);
1012         }
1013 
1014         // Compute precision
1015         int32_t leading = precision - 1;
1016         for (; leading >= 0 && fBCD.bcdBytes.ptr[leading] == 0; leading--);
1017         precision = leading + 1;
1018 
1019         // Switch storage mechanism if possible
1020         if (precision <= 16) {
1021             switchStorage();
1022         }
1023 
1024     } else {
1025         if (fBCD.bcdLong == 0L) {
1026             // Number is zero
1027             setBcdToZero();
1028             return;
1029         }
1030 
1031         // Compact the number (remove trailing zeros)
1032         // TODO: Use a more efficient algorithm here and below. There is a logarithmic one.
1033         int32_t delta = 0;
1034         for (; delta < precision && getDigitPos(delta) == 0; delta++);
1035         fBCD.bcdLong >>= delta * 4;
1036         scale += delta;
1037 
1038         // Compute precision
1039         int32_t leading = precision - 1;
1040         for (; leading >= 0 && getDigitPos(leading) == 0; leading--);
1041         precision = leading + 1;
1042     }
1043 }
1044 
ensureCapacity()1045 void DecimalQuantity::ensureCapacity() {
1046     ensureCapacity(40);
1047 }
1048 
ensureCapacity(int32_t capacity)1049 void DecimalQuantity::ensureCapacity(int32_t capacity) {
1050     if (capacity == 0) { return; }
1051     int32_t oldCapacity = usingBytes ? fBCD.bcdBytes.len : 0;
1052     if (!usingBytes) {
1053         // TODO: There is nothing being done to check for memory allocation failures.
1054         // TODO: Consider indexing by nybbles instead of bytes in C++, so that we can
1055         // make these arrays half the size.
1056         fBCD.bcdBytes.ptr = static_cast<int8_t*>(uprv_malloc(capacity * sizeof(int8_t)));
1057         fBCD.bcdBytes.len = capacity;
1058         // Initialize the byte array to zeros (this is done automatically in Java)
1059         uprv_memset(fBCD.bcdBytes.ptr, 0, capacity * sizeof(int8_t));
1060     } else if (oldCapacity < capacity) {
1061         auto bcd1 = static_cast<int8_t*>(uprv_malloc(capacity * 2 * sizeof(int8_t)));
1062         uprv_memcpy(bcd1, fBCD.bcdBytes.ptr, oldCapacity * sizeof(int8_t));
1063         // Initialize the rest of the byte array to zeros (this is done automatically in Java)
1064         uprv_memset(bcd1 + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t));
1065         uprv_free(fBCD.bcdBytes.ptr);
1066         fBCD.bcdBytes.ptr = bcd1;
1067         fBCD.bcdBytes.len = capacity * 2;
1068     }
1069     usingBytes = true;
1070 }
1071 
switchStorage()1072 void DecimalQuantity::switchStorage() {
1073     if (usingBytes) {
1074         // Change from bytes to long
1075         uint64_t bcdLong = 0L;
1076         for (int i = precision - 1; i >= 0; i--) {
1077             bcdLong <<= 4;
1078             bcdLong |= fBCD.bcdBytes.ptr[i];
1079         }
1080         uprv_free(fBCD.bcdBytes.ptr);
1081         fBCD.bcdBytes.ptr = nullptr;
1082         fBCD.bcdLong = bcdLong;
1083         usingBytes = false;
1084     } else {
1085         // Change from long to bytes
1086         // Copy the long into a local variable since it will get munged when we allocate the bytes
1087         uint64_t bcdLong = fBCD.bcdLong;
1088         ensureCapacity();
1089         for (int i = 0; i < precision; i++) {
1090             fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(bcdLong & 0xf);
1091             bcdLong >>= 4;
1092         }
1093         U_ASSERT(usingBytes);
1094     }
1095 }
1096 
copyBcdFrom(const DecimalQuantity & other)1097 void DecimalQuantity::copyBcdFrom(const DecimalQuantity &other) {
1098     setBcdToZero();
1099     if (other.usingBytes) {
1100         ensureCapacity(other.precision);
1101         uprv_memcpy(fBCD.bcdBytes.ptr, other.fBCD.bcdBytes.ptr, other.precision * sizeof(int8_t));
1102     } else {
1103         fBCD.bcdLong = other.fBCD.bcdLong;
1104     }
1105 }
1106 
moveBcdFrom(DecimalQuantity & other)1107 void DecimalQuantity::moveBcdFrom(DecimalQuantity &other) {
1108     setBcdToZero();
1109     if (other.usingBytes) {
1110         usingBytes = true;
1111         fBCD.bcdBytes.ptr = other.fBCD.bcdBytes.ptr;
1112         fBCD.bcdBytes.len = other.fBCD.bcdBytes.len;
1113         // Take ownership away from the old instance:
1114         other.fBCD.bcdBytes.ptr = nullptr;
1115         other.usingBytes = false;
1116     } else {
1117         fBCD.bcdLong = other.fBCD.bcdLong;
1118     }
1119 }
1120 
checkHealth() const1121 const char16_t* DecimalQuantity::checkHealth() const {
1122     if (usingBytes) {
1123         if (precision == 0) { return u"Zero precision but we are in byte mode"; }
1124         int32_t capacity = fBCD.bcdBytes.len;
1125         if (precision > capacity) { return u"Precision exceeds length of byte array"; }
1126         if (getDigitPos(precision - 1) == 0) { return u"Most significant digit is zero in byte mode"; }
1127         if (getDigitPos(0) == 0) { return u"Least significant digit is zero in long mode"; }
1128         for (int i = 0; i < precision; i++) {
1129             if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in byte array"; }
1130             if (getDigitPos(i) < 0) { return u"Digit below 0 in byte array"; }
1131         }
1132         for (int i = precision; i < capacity; i++) {
1133             if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in byte array"; }
1134         }
1135     } else {
1136         if (precision == 0 && fBCD.bcdLong != 0) {
1137             return u"Value in bcdLong even though precision is zero";
1138         }
1139         if (precision > 16) { return u"Precision exceeds length of long"; }
1140         if (precision != 0 && getDigitPos(precision - 1) == 0) {
1141             return u"Most significant digit is zero in long mode";
1142         }
1143         if (precision != 0 && getDigitPos(0) == 0) {
1144             return u"Least significant digit is zero in long mode";
1145         }
1146         for (int i = 0; i < precision; i++) {
1147             if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in long"; }
1148             if (getDigitPos(i) < 0) { return u"Digit below 0 in long (?!)"; }
1149         }
1150         for (int i = precision; i < 16; i++) {
1151             if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in long"; }
1152         }
1153     }
1154 
1155     // No error
1156     return nullptr;
1157 }
1158 
operator ==(const DecimalQuantity & other) const1159 bool DecimalQuantity::operator==(const DecimalQuantity& other) const {
1160     bool basicEquals =
1161             scale == other.scale
1162             && precision == other.precision
1163             && flags == other.flags
1164             && lOptPos == other.lOptPos
1165             && lReqPos == other.lReqPos
1166             && rReqPos == other.rReqPos
1167             && rOptPos == other.rOptPos
1168             && isApproximate == other.isApproximate;
1169     if (!basicEquals) {
1170         return false;
1171     }
1172 
1173     if (precision == 0) {
1174         return true;
1175     } else if (isApproximate) {
1176         return origDouble == other.origDouble && origDelta == other.origDelta;
1177     } else {
1178         for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
1179             if (getDigit(m) != other.getDigit(m)) {
1180                 return false;
1181             }
1182         }
1183         return true;
1184     }
1185 }
1186 
toString() const1187 UnicodeString DecimalQuantity::toString() const {
1188     MaybeStackArray<char, 30> digits(precision + 1);
1189     for (int32_t i = 0; i < precision; i++) {
1190         digits[i] = getDigitPos(precision - i - 1) + '0';
1191     }
1192     digits[precision] = 0; // terminate buffer
1193     char buffer8[100];
1194     snprintf(
1195             buffer8,
1196             sizeof(buffer8),
1197             "<DecimalQuantity %d:%d:%d:%d %s %s%s%s%d>",
1198             (lOptPos > 999 ? 999 : lOptPos),
1199             lReqPos,
1200             rReqPos,
1201             (rOptPos < -999 ? -999 : rOptPos),
1202             (usingBytes ? "bytes" : "long"),
1203             (isNegative() ? "-" : ""),
1204             (precision == 0 ? "0" : digits.getAlias()),
1205             "E",
1206             scale);
1207     return UnicodeString(buffer8, -1, US_INV);
1208 }
1209 
1210 #endif /* #if !UCONFIG_NO_FORMATTING */
1211