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