1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 #include "unicode/utypes.h"
6 #if !UCONFIG_NO_FORMATTING
13 #include "unicode/plurrule.h"
15 #include "number_decnum.h"
17 #include "number_decimalquantity.h"
18 #include "number_roundingutils.h"
19 #include "double-conversion.h"
21 #include "number_utils.h"
25 using namespace icu::number
;
26 using namespace icu::number::impl
;
28 using icu::double_conversion::DoubleToStringConverter
;
29 using icu::double_conversion::StringToDoubleConverter
;
33 int8_t NEGATIVE_FLAG
= 1;
34 int8_t INFINITY_FLAG
= 2;
37 /** Helper function for safe subtraction (no overflow). */
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
; }
46 static double DOUBLE_MULTIPLIERS
[] = {
72 icu::IFixedDecimal::~IFixedDecimal() = default;
74 DecimalQuantity::DecimalQuantity() {
79 DecimalQuantity::~DecimalQuantity() {
81 uprv_free(fBCD
.bcdBytes
.ptr
);
82 fBCD
.bcdBytes
.ptr
= nullptr;
87 DecimalQuantity::DecimalQuantity(const DecimalQuantity
&other
) {
91 DecimalQuantity::DecimalQuantity(DecimalQuantity
&& src
) U_NOEXCEPT
{
92 *this = std::move(src
);
95 DecimalQuantity
&DecimalQuantity::operator=(const DecimalQuantity
&other
) {
100 copyFieldsFrom(other
);
104 DecimalQuantity
& DecimalQuantity::operator=(DecimalQuantity
&& src
) U_NOEXCEPT
{
113 void DecimalQuantity::copyFieldsFrom(const DecimalQuantity
& other
) {
115 lReqPos
= other
.lReqPos
;
116 rReqPos
= other
.rReqPos
;
118 precision
= other
.precision
;
120 origDouble
= other
.origDouble
;
121 origDelta
= other
.origDelta
;
122 isApproximate
= other
.isApproximate
;
125 void DecimalQuantity::clear() {
129 setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data
132 void DecimalQuantity::setMinInteger(int32_t minInt
) {
133 // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
134 U_ASSERT(minInt
>= 0);
136 // Special behavior: do not set minInt to be less than what is already set.
137 // This is so significant digits rounding can set the integer length.
138 if (minInt
< lReqPos
) {
142 // Save values into internal state
146 void DecimalQuantity::setMinFraction(int32_t minFrac
) {
147 // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
148 U_ASSERT(minFrac
>= 0);
150 // Save values into internal state
151 // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
155 void DecimalQuantity::applyMaxInteger(int32_t maxInt
) {
156 // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
157 U_ASSERT(maxInt
>= 0);
159 if (precision
== 0) {
163 if (maxInt
<= scale
) {
168 int32_t magnitude
= getMagnitude();
169 if (maxInt
<= magnitude
) {
170 popFromLeft(magnitude
- maxInt
+ 1);
175 uint64_t DecimalQuantity::getPositionFingerprint() const {
176 uint64_t fingerprint
= 0;
177 fingerprint
^= (lReqPos
<< 16);
178 fingerprint
^= (static_cast<uint64_t>(rReqPos
) << 32);
182 void DecimalQuantity::roundToIncrement(double roundingIncrement
, RoundingMode roundingMode
,
183 UErrorCode
& status
) {
184 // Do not call this method with an increment having only a 1 or a 5 digit!
185 // Use a more efficient call to either roundToMagnitude() or roundToNickel().
186 // Check a few popular rounding increments; a more thorough check is in Java.
187 U_ASSERT(roundingIncrement
!= 0.01);
188 U_ASSERT(roundingIncrement
!= 0.05);
189 U_ASSERT(roundingIncrement
!= 0.1);
190 U_ASSERT(roundingIncrement
!= 0.5);
191 U_ASSERT(roundingIncrement
!= 1);
192 U_ASSERT(roundingIncrement
!= 5);
195 incrementDN
.setTo(roundingIncrement
, status
);
196 if (U_FAILURE(status
)) { return; }
198 // Divide this DecimalQuantity by the increment, round, then multiply back.
199 divideBy(incrementDN
, status
);
200 if (U_FAILURE(status
)) { return; }
201 roundToMagnitude(0, roundingMode
, status
);
202 if (U_FAILURE(status
)) { return; }
203 multiplyBy(incrementDN
, status
);
204 if (U_FAILURE(status
)) { return; }
207 void DecimalQuantity::multiplyBy(const DecNum
& multiplicand
, UErrorCode
& status
) {
208 if (isInfinite() || isZero() || isNaN()) {
211 // Convert to DecNum, multiply, and convert back.
213 toDecNum(decnum
, status
);
214 if (U_FAILURE(status
)) { return; }
215 decnum
.multiplyBy(multiplicand
, status
);
216 if (U_FAILURE(status
)) { return; }
217 setToDecNum(decnum
, status
);
220 void DecimalQuantity::divideBy(const DecNum
& divisor
, UErrorCode
& status
) {
221 if (isInfinite() || isZero() || isNaN()) {
224 // Convert to DecNum, multiply, and convert back.
226 toDecNum(decnum
, status
);
227 if (U_FAILURE(status
)) { return; }
228 decnum
.divideBy(divisor
, status
);
229 if (U_FAILURE(status
)) { return; }
230 setToDecNum(decnum
, status
);
233 void DecimalQuantity::negate() {
234 flags
^= NEGATIVE_FLAG
;
237 int32_t DecimalQuantity::getMagnitude() const {
238 U_ASSERT(precision
!= 0);
239 return scale
+ precision
- 1;
242 bool DecimalQuantity::adjustMagnitude(int32_t delta
) {
243 if (precision
!= 0) {
244 // i.e., scale += delta; origDelta += delta
245 bool overflow
= uprv_add32_overflow(scale
, delta
, &scale
);
246 overflow
= uprv_add32_overflow(origDelta
, delta
, &origDelta
) || overflow
;
247 // Make sure that precision + scale won't overflow, either
249 overflow
= overflow
|| uprv_add32_overflow(scale
, precision
, &dummy
);
255 double DecimalQuantity::getPluralOperand(PluralOperand operand
) const {
256 // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
257 // See the comment at the top of this file explaining the "isApproximate" field.
258 U_ASSERT(!isApproximate
);
261 case PLURAL_OPERAND_I
:
262 // Invert the negative sign if necessary
263 return static_cast<double>(isNegative() ? -toLong(true) : toLong(true));
264 case PLURAL_OPERAND_F
:
265 return static_cast<double>(toFractionLong(true));
266 case PLURAL_OPERAND_T
:
267 return static_cast<double>(toFractionLong(false));
268 case PLURAL_OPERAND_V
:
269 return fractionCount();
270 case PLURAL_OPERAND_W
:
271 return fractionCountWithoutTrailingZeros();
273 return std::abs(toDouble());
277 bool DecimalQuantity::hasIntegerValue() const {
281 int32_t DecimalQuantity::getUpperDisplayMagnitude() const {
282 // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
283 // See the comment in the header file explaining the "isApproximate" field.
284 U_ASSERT(!isApproximate
);
286 int32_t magnitude
= scale
+ precision
;
287 int32_t result
= (lReqPos
> magnitude
) ? lReqPos
: magnitude
;
291 int32_t DecimalQuantity::getLowerDisplayMagnitude() const {
292 // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
293 // See the comment in the header file explaining the "isApproximate" field.
294 U_ASSERT(!isApproximate
);
296 int32_t magnitude
= scale
;
297 int32_t result
= (rReqPos
< magnitude
) ? rReqPos
: magnitude
;
301 int8_t DecimalQuantity::getDigit(int32_t magnitude
) const {
302 // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
303 // See the comment at the top of this file explaining the "isApproximate" field.
304 U_ASSERT(!isApproximate
);
306 return getDigitPos(magnitude
- scale
);
309 int32_t DecimalQuantity::fractionCount() const {
310 return -getLowerDisplayMagnitude();
313 int32_t DecimalQuantity::fractionCountWithoutTrailingZeros() const {
314 return -scale
> 0 ? -scale
: 0; // max(-scale, 0)
317 bool DecimalQuantity::isNegative() const {
318 return (flags
& NEGATIVE_FLAG
) != 0;
321 int8_t DecimalQuantity::signum() const {
322 return isNegative() ? -1 : isZero() ? 0 : 1;
325 bool DecimalQuantity::isInfinite() const {
326 return (flags
& INFINITY_FLAG
) != 0;
329 bool DecimalQuantity::isNaN() const {
330 return (flags
& NAN_FLAG
) != 0;
333 bool DecimalQuantity::isZero() const {
334 return precision
== 0;
337 DecimalQuantity
&DecimalQuantity::setToInt(int32_t n
) {
340 if (n
== INT32_MIN
) {
341 flags
|= NEGATIVE_FLAG
;
342 // leave as INT32_MIN; handled below in _setToInt()
344 flags
|= NEGATIVE_FLAG
;
354 void DecimalQuantity::_setToInt(int32_t n
) {
355 if (n
== INT32_MIN
) {
356 readLongToBcd(-static_cast<int64_t>(n
));
362 DecimalQuantity
&DecimalQuantity::setToLong(int64_t n
) {
365 if (n
< 0 && n
> INT64_MIN
) {
366 flags
|= NEGATIVE_FLAG
;
376 void DecimalQuantity::_setToLong(int64_t n
) {
377 if (n
== INT64_MIN
) {
379 UErrorCode localStatus
= U_ZERO_ERROR
;
380 decnum
.setTo("9.223372036854775808E+18", localStatus
);
381 if (U_FAILURE(localStatus
)) { return; } // unexpected
382 flags
|= NEGATIVE_FLAG
;
383 readDecNumberToBcd(decnum
);
384 } else if (n
<= INT32_MAX
) {
385 readIntToBcd(static_cast<int32_t>(n
));
391 DecimalQuantity
&DecimalQuantity::setToDouble(double n
) {
394 // signbit() from <math.h> handles +0.0 vs -0.0
395 if (std::signbit(n
)) {
396 flags
|= NEGATIVE_FLAG
;
399 if (std::isnan(n
) != 0) {
401 } else if (std::isfinite(n
) == 0) {
402 flags
|= INFINITY_FLAG
;
410 void DecimalQuantity::_setToDoubleFast(double n
) {
411 isApproximate
= true;
415 // Make sure the double is an IEEE 754 double. If not, fall back to the slow path right now.
416 // TODO: Make a fast path for other types of doubles.
417 if (!std::numeric_limits
<double>::is_iec559
) {
418 convertToAccurateDouble();
419 // Turn off the approximate double flag, since the value is now exact.
420 isApproximate
= false;
425 // To get the bits from the double, use memcpy, which takes care of endianness.
427 uprv_memcpy(&ieeeBits
, &n
, sizeof(n
));
428 int32_t exponent
= static_cast<int32_t>((ieeeBits
& 0x7ff0000000000000L
) >> 52) - 0x3ff;
430 // Not all integers can be represented exactly for exponent > 52
431 if (exponent
<= 52 && static_cast<int64_t>(n
) == n
) {
432 _setToLong(static_cast<int64_t>(n
));
436 // 3.3219... is log2(10)
437 auto fracLength
= static_cast<int32_t> ((52 - exponent
) / 3.32192809489);
438 if (fracLength
>= 0) {
439 int32_t i
= fracLength
;
440 // 1e22 is the largest exact double.
441 for (; i
>= 22; i
-= 22) n
*= 1e22
;
442 n
*= DOUBLE_MULTIPLIERS
[i
];
444 int32_t i
= fracLength
;
445 // 1e22 is the largest exact double.
446 for (; i
<= -22; i
+= 22) n
/= 1e22
;
447 n
/= DOUBLE_MULTIPLIERS
[-i
];
449 auto result
= static_cast<int64_t>(std::round(n
));
456 void DecimalQuantity::convertToAccurateDouble() {
457 U_ASSERT(origDouble
!= 0);
458 int32_t delta
= origDelta
;
460 // Call the slow oracle function (Double.toString in Java, DoubleToAscii in C++).
461 char buffer
[DoubleToStringConverter::kBase10MaximalLength
+ 1];
462 bool sign
; // unused; always positive
465 DoubleToStringConverter::DoubleToAscii(
467 DoubleToStringConverter::DtoaMode::SHORTEST
,
477 readDoubleConversionToBcd(buffer
, length
, point
);
479 explicitExactDouble
= true;
482 DecimalQuantity
&DecimalQuantity::setToDecNumber(StringPiece n
, UErrorCode
& status
) {
486 // Compute the decNumber representation
488 decnum
.setTo(n
, status
);
490 _setToDecNum(decnum
, status
);
494 DecimalQuantity
& DecimalQuantity::setToDecNum(const DecNum
& decnum
, UErrorCode
& status
) {
498 _setToDecNum(decnum
, status
);
502 void DecimalQuantity::_setToDecNum(const DecNum
& decnum
, UErrorCode
& status
) {
503 if (U_FAILURE(status
)) { return; }
504 if (decnum
.isNegative()) {
505 flags
|= NEGATIVE_FLAG
;
507 if (!decnum
.isZero()) {
508 readDecNumberToBcd(decnum
);
513 int64_t DecimalQuantity::toLong(bool truncateIfOverflow
) const {
514 // NOTE: Call sites should be guarded by fitsInLong(), like this:
515 // if (dq.fitsInLong()) { /* use dq.toLong() */ } else { /* use some fallback */ }
516 // Fallback behavior upon truncateIfOverflow is to truncate at 17 digits.
517 uint64_t result
= 0L;
518 int32_t upperMagnitude
= scale
+ precision
- 1;
519 if (truncateIfOverflow
) {
520 upperMagnitude
= std::min(upperMagnitude
, 17);
522 for (int32_t magnitude
= upperMagnitude
; magnitude
>= 0; magnitude
--) {
523 result
= result
* 10 + getDigitPos(magnitude
- scale
);
526 return static_cast<int64_t>(0LL - result
); // i.e., -result
528 return static_cast<int64_t>(result
);
531 uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros
) const {
532 uint64_t result
= 0L;
533 int32_t magnitude
= -1;
534 int32_t lowerMagnitude
= scale
;
535 if (includeTrailingZeros
) {
536 lowerMagnitude
= std::min(lowerMagnitude
, rReqPos
);
538 for (; magnitude
>= lowerMagnitude
&& result
<= 1e18L
; magnitude
--) {
539 result
= result
* 10 + getDigitPos(magnitude
- scale
);
541 // Remove trailing zeros; this can happen during integer overflow cases.
542 if (!includeTrailingZeros
) {
543 while (result
> 0 && (result
% 10) == 0) {
550 bool DecimalQuantity::fitsInLong(bool ignoreFraction
) const {
554 if (scale
< 0 && !ignoreFraction
) {
557 int magnitude
= getMagnitude();
558 if (magnitude
< 18) {
561 if (magnitude
> 18) {
564 // Hard case: the magnitude is 10^18.
565 // The largest int64 is: 9,223,372,036,854,775,807
566 for (int p
= 0; p
< precision
; p
++) {
567 int8_t digit
= getDigit(18 - p
);
568 static int8_t INT64_BCD
[] = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 };
569 if (digit
< INT64_BCD
[p
]) {
571 } else if (digit
> INT64_BCD
[p
]) {
575 // Exactly equal to max long plus one.
579 double DecimalQuantity::toDouble() const {
580 // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
581 // See the comment in the header file explaining the "isApproximate" field.
582 U_ASSERT(!isApproximate
);
586 } else if (isInfinite()) {
587 return isNegative() ? -INFINITY
: INFINITY
;
590 // We are processing well-formed input, so we don't need any special options to StringToDoubleConverter.
591 StringToDoubleConverter
converter(0, 0, 0, "", "");
592 UnicodeString numberString
= this->toScientificString();
594 return converter
.StringToDouble(
595 reinterpret_cast<const uint16_t*>(numberString
.getBuffer()),
596 numberString
.length(),
600 void DecimalQuantity::toDecNum(DecNum
& output
, UErrorCode
& status
) const {
601 // Special handling for zero
602 if (precision
== 0) {
603 output
.setTo("0", status
);
606 // Use the BCD constructor. We need to do a little bit of work to convert, though.
607 // The decNumber constructor expects most-significant first, but we store least-significant first.
608 MaybeStackArray
<uint8_t, 20> ubcd(precision
);
609 for (int32_t m
= 0; m
< precision
; m
++) {
610 ubcd
[precision
- m
- 1] = static_cast<uint8_t>(getDigitPos(m
));
612 output
.setTo(ubcd
.getAlias(), precision
, scale
, isNegative(), status
);
615 void DecimalQuantity::truncate() {
623 void DecimalQuantity::roundToNickel(int32_t magnitude
, RoundingMode roundingMode
, UErrorCode
& status
) {
624 roundToMagnitude(magnitude
, roundingMode
, true, status
);
627 void DecimalQuantity::roundToMagnitude(int32_t magnitude
, RoundingMode roundingMode
, UErrorCode
& status
) {
628 roundToMagnitude(magnitude
, roundingMode
, false, status
);
631 void DecimalQuantity::roundToMagnitude(int32_t magnitude
, RoundingMode roundingMode
, bool nickel
, UErrorCode
& status
) {
632 // The position in the BCD at which rounding will be performed; digits to the right of position
633 // will be rounded away.
634 int position
= safeSubtract(magnitude
, scale
);
636 // "trailing" = least significant digit to the left of rounding
637 int8_t trailingDigit
= getDigitPos(position
);
639 if (position
<= 0 && !isApproximate
&& (!nickel
|| trailingDigit
== 0 || trailingDigit
== 5)) {
640 // All digits are to the left of the rounding magnitude.
641 } else if (precision
== 0) {
642 // No rounding for zero.
644 // Perform rounding logic.
645 // "leading" = most significant digit to the right of rounding
646 int8_t leadingDigit
= getDigitPos(safeSubtract(position
, 1));
648 // Compute which section of the number we are in.
649 // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles)
650 // LOWER means we are between the bottom edge and the midpoint, like 1.391
651 // MIDPOINT means we are exactly in the middle, like 1.500
652 // UPPER means we are between the midpoint and the top edge, like 1.916
653 roundingutils::Section section
;
654 if (!isApproximate
) {
655 if (nickel
&& trailingDigit
!= 2 && trailingDigit
!= 7) {
656 // Nickel rounding, and not at .02x or .07x
657 if (trailingDigit
< 2) {
658 // .00, .01 => down to .00
659 section
= roundingutils::SECTION_LOWER
;
660 } else if (trailingDigit
< 5) {
661 // .03, .04 => up to .05
662 section
= roundingutils::SECTION_UPPER
;
663 } else if (trailingDigit
< 7) {
664 // .05, .06 => down to .05
665 section
= roundingutils::SECTION_LOWER
;
667 // .08, .09 => up to .10
668 section
= roundingutils::SECTION_UPPER
;
670 } else if (leadingDigit
< 5) {
671 // Includes nickel rounding .020-.024 and .070-.074
672 section
= roundingutils::SECTION_LOWER
;
673 } else if (leadingDigit
> 5) {
674 // Includes nickel rounding .026-.029 and .076-.079
675 section
= roundingutils::SECTION_UPPER
;
677 // Includes nickel rounding .025 and .075
678 section
= roundingutils::SECTION_MIDPOINT
;
679 for (int p
= safeSubtract(position
, 2); p
>= 0; p
--) {
680 if (getDigitPos(p
) != 0) {
681 section
= roundingutils::SECTION_UPPER
;
687 int32_t p
= safeSubtract(position
, 2);
688 int32_t minP
= uprv_max(0, precision
- 14);
689 if (leadingDigit
== 0 && (!nickel
|| trailingDigit
== 0 || trailingDigit
== 5)) {
690 section
= roundingutils::SECTION_LOWER_EDGE
;
691 for (; p
>= minP
; p
--) {
692 if (getDigitPos(p
) != 0) {
693 section
= roundingutils::SECTION_LOWER
;
697 } else if (leadingDigit
== 4 && (!nickel
|| trailingDigit
== 2 || trailingDigit
== 7)) {
698 section
= roundingutils::SECTION_MIDPOINT
;
699 for (; p
>= minP
; p
--) {
700 if (getDigitPos(p
) != 9) {
701 section
= roundingutils::SECTION_LOWER
;
705 } else if (leadingDigit
== 5 && (!nickel
|| trailingDigit
== 2 || trailingDigit
== 7)) {
706 section
= roundingutils::SECTION_MIDPOINT
;
707 for (; p
>= minP
; p
--) {
708 if (getDigitPos(p
) != 0) {
709 section
= roundingutils::SECTION_UPPER
;
713 } else if (leadingDigit
== 9 && (!nickel
|| trailingDigit
== 4 || trailingDigit
== 9)) {
714 section
= roundingutils::SECTION_UPPER_EDGE
;
715 for (; p
>= minP
; p
--) {
716 if (getDigitPos(p
) != 9) {
717 section
= roundingutils::SECTION_UPPER
;
721 } else if (nickel
&& trailingDigit
!= 2 && trailingDigit
!= 7) {
722 // Nickel rounding, and not at .02x or .07x
723 if (trailingDigit
< 2) {
724 // .00, .01 => down to .00
725 section
= roundingutils::SECTION_LOWER
;
726 } else if (trailingDigit
< 5) {
727 // .03, .04 => up to .05
728 section
= roundingutils::SECTION_UPPER
;
729 } else if (trailingDigit
< 7) {
730 // .05, .06 => down to .05
731 section
= roundingutils::SECTION_LOWER
;
733 // .08, .09 => up to .10
734 section
= roundingutils::SECTION_UPPER
;
736 } else if (leadingDigit
< 5) {
737 // Includes nickel rounding .020-.024 and .070-.074
738 section
= roundingutils::SECTION_LOWER
;
740 // Includes nickel rounding .026-.029 and .076-.079
741 section
= roundingutils::SECTION_UPPER
;
744 bool roundsAtMidpoint
= roundingutils::roundsAtMidpoint(roundingMode
);
745 if (safeSubtract(position
, 1) < precision
- 14 ||
746 (roundsAtMidpoint
&& section
== roundingutils::SECTION_MIDPOINT
) ||
747 (!roundsAtMidpoint
&& section
< 0 /* i.e. at upper or lower edge */)) {
748 // Oops! This means that we have to get the exact representation of the double,
749 // because the zone of uncertainty is along the rounding boundary.
750 convertToAccurateDouble();
751 roundToMagnitude(magnitude
, roundingMode
, nickel
, status
); // start over
755 // Turn off the approximate double flag, since the value is now confirmed to be exact.
756 isApproximate
= false;
760 if (position
<= 0 && (!nickel
|| trailingDigit
== 0 || trailingDigit
== 5)) {
761 // All digits are to the left of the rounding magnitude.
765 // Good to continue rounding.
766 if (section
== -1) { section
= roundingutils::SECTION_LOWER
; }
767 if (section
== -2) { section
= roundingutils::SECTION_UPPER
; }
770 // Nickel rounding "half even" goes to the nearest whole (away from the 5).
772 ? (trailingDigit
< 2 || trailingDigit
> 7
773 || (trailingDigit
== 2 && section
!= roundingutils::SECTION_UPPER
)
774 || (trailingDigit
== 7 && section
== roundingutils::SECTION_UPPER
))
775 : (trailingDigit
% 2) == 0;
777 bool roundDown
= roundingutils::getRoundingDirection(isEven
,
782 if (U_FAILURE(status
)) {
786 // Perform truncation
787 if (position
>= precision
) {
791 shiftRight(position
);
795 if (trailingDigit
< 5 && roundDown
) {
799 } else if (trailingDigit
>= 5 && !roundDown
) {
802 // do not return: use the bubbling logic below
805 // compact not necessary: digit at position 0 is nonzero
810 // Bubble the result to the higher digits
812 if (trailingDigit
== 9) {
814 // Note: in the long implementation, the most digits BCD can have at this point is
815 // 15, so bubblePos <= 15 and getDigitPos(bubblePos) is safe.
816 for (; getDigitPos(bubblePos
) == 9; bubblePos
++) {}
817 shiftRight(bubblePos
); // shift off the trailing 9s
819 int8_t digit0
= getDigitPos(0);
820 U_ASSERT(digit0
!= 9);
821 setDigitPos(0, static_cast<int8_t>(digit0
+ 1));
822 precision
+= 1; // in case an extra digit got added
829 void DecimalQuantity::roundToInfinity() {
831 convertToAccurateDouble();
835 void DecimalQuantity::appendDigit(int8_t value
, int32_t leadingZeros
, bool appendAsInteger
) {
836 U_ASSERT(leadingZeros
>= 0);
838 // Zero requires special handling to maintain the invariant that the least-significant digit
839 // in the BCD is nonzero.
841 if (appendAsInteger
&& precision
!= 0) {
842 scale
+= leadingZeros
+ 1;
847 // Deal with trailing zeros
849 leadingZeros
+= scale
;
850 if (appendAsInteger
) {
856 shiftLeft(leadingZeros
+ 1);
857 setDigitPos(0, value
);
859 // Fix scale if in integer mode
860 if (appendAsInteger
) {
861 scale
+= leadingZeros
+ 1;
865 UnicodeString
DecimalQuantity::toPlainString() const {
866 U_ASSERT(!isApproximate
);
871 if (precision
== 0 || getMagnitude() < 0) {
874 for (int m
= getUpperDisplayMagnitude(); m
>= getLowerDisplayMagnitude(); m
--) {
875 if (m
== -1) { sb
.append(u
'.'); }
876 sb
.append(getDigit(m
) + u
'0');
881 UnicodeString
DecimalQuantity::toScientificString() const {
882 U_ASSERT(!isApproximate
);
883 UnicodeString result
;
887 if (precision
== 0) {
888 result
.append(u
"0E+0", -1);
891 int32_t upperPos
= precision
- 1;
892 int32_t lowerPos
= 0;
893 int32_t p
= upperPos
;
894 result
.append(u
'0' + getDigitPos(p
));
895 if ((--p
) >= lowerPos
) {
897 for (; p
>= lowerPos
; p
--) {
898 result
.append(u
'0' + getDigitPos(p
));
902 int32_t _scale
= upperPos
+ scale
;
903 if (_scale
== INT32_MIN
) {
904 result
.append({u
"-2147483648", -1});
906 } else if (_scale
< 0) {
915 int32_t insertIndex
= result
.length();
917 std::div_t res
= std::div(_scale
, 10);
918 result
.insert(insertIndex
, u
'0' + res
.rem
);
924 ////////////////////////////////////////////////////
925 /// End of DecimalQuantity_AbstractBCD.java ///
926 /// Start of DecimalQuantity_DualStorageBCD.java ///
927 ////////////////////////////////////////////////////
929 int8_t DecimalQuantity::getDigitPos(int32_t position
) const {
931 if (position
< 0 || position
>= precision
) { return 0; }
932 return fBCD
.bcdBytes
.ptr
[position
];
934 if (position
< 0 || position
>= 16) { return 0; }
935 return (int8_t) ((fBCD
.bcdLong
>> (position
* 4)) & 0xf);
939 void DecimalQuantity::setDigitPos(int32_t position
, int8_t value
) {
940 U_ASSERT(position
>= 0);
942 ensureCapacity(position
+ 1);
943 fBCD
.bcdBytes
.ptr
[position
] = value
;
944 } else if (position
>= 16) {
946 ensureCapacity(position
+ 1);
947 fBCD
.bcdBytes
.ptr
[position
] = value
;
949 int shift
= position
* 4;
950 fBCD
.bcdLong
= (fBCD
.bcdLong
& ~(0xfL
<< shift
)) | ((long) value
<< shift
);
954 void DecimalQuantity::shiftLeft(int32_t numDigits
) {
955 if (!usingBytes
&& precision
+ numDigits
> 16) {
959 ensureCapacity(precision
+ numDigits
);
960 int i
= precision
+ numDigits
- 1;
961 for (; i
>= numDigits
; i
--) {
962 fBCD
.bcdBytes
.ptr
[i
] = fBCD
.bcdBytes
.ptr
[i
- numDigits
];
964 for (; i
>= 0; i
--) {
965 fBCD
.bcdBytes
.ptr
[i
] = 0;
968 fBCD
.bcdLong
<<= (numDigits
* 4);
971 precision
+= numDigits
;
974 void DecimalQuantity::shiftRight(int32_t numDigits
) {
977 for (; i
< precision
- numDigits
; i
++) {
978 fBCD
.bcdBytes
.ptr
[i
] = fBCD
.bcdBytes
.ptr
[i
+ numDigits
];
980 for (; i
< precision
; i
++) {
981 fBCD
.bcdBytes
.ptr
[i
] = 0;
984 fBCD
.bcdLong
>>= (numDigits
* 4);
987 precision
-= numDigits
;
990 void DecimalQuantity::popFromLeft(int32_t numDigits
) {
991 U_ASSERT(numDigits
<= precision
);
993 int i
= precision
- 1;
994 for (; i
>= precision
- numDigits
; i
--) {
995 fBCD
.bcdBytes
.ptr
[i
] = 0;
998 fBCD
.bcdLong
&= (static_cast<uint64_t>(1) << ((precision
- numDigits
) * 4)) - 1;
1000 precision
-= numDigits
;
1003 void DecimalQuantity::setBcdToZero() {
1005 uprv_free(fBCD
.bcdBytes
.ptr
);
1006 fBCD
.bcdBytes
.ptr
= nullptr;
1012 isApproximate
= false;
1017 void DecimalQuantity::readIntToBcd(int32_t n
) {
1019 // ints always fit inside the long implementation.
1020 uint64_t result
= 0L;
1022 for (; n
!= 0; n
/= 10, i
--) {
1023 result
= (result
>> 4) + ((static_cast<uint64_t>(n
) % 10) << 60);
1025 U_ASSERT(!usingBytes
);
1026 fBCD
.bcdLong
= result
>> (i
* 4);
1031 void DecimalQuantity::readLongToBcd(int64_t n
) {
1033 if (n
>= 10000000000000000L) {
1036 for (; n
!= 0L; n
/= 10L, i
++) {
1037 fBCD
.bcdBytes
.ptr
[i
] = static_cast<int8_t>(n
% 10);
1039 U_ASSERT(usingBytes
);
1043 uint64_t result
= 0L;
1045 for (; n
!= 0L; n
/= 10L, i
--) {
1046 result
= (result
>> 4) + ((n
% 10) << 60);
1049 U_ASSERT(!usingBytes
);
1050 fBCD
.bcdLong
= result
>> (i
* 4);
1056 void DecimalQuantity::readDecNumberToBcd(const DecNum
& decnum
) {
1057 const decNumber
* dn
= decnum
.getRawDecNumber();
1058 if (dn
->digits
> 16) {
1059 ensureCapacity(dn
->digits
);
1060 for (int32_t i
= 0; i
< dn
->digits
; i
++) {
1061 fBCD
.bcdBytes
.ptr
[i
] = dn
->lsu
[i
];
1064 uint64_t result
= 0L;
1065 for (int32_t i
= 0; i
< dn
->digits
; i
++) {
1066 result
|= static_cast<uint64_t>(dn
->lsu
[i
]) << (4 * i
);
1068 fBCD
.bcdLong
= result
;
1070 scale
= dn
->exponent
;
1071 precision
= dn
->digits
;
1074 void DecimalQuantity::readDoubleConversionToBcd(
1075 const char* buffer
, int32_t length
, int32_t point
) {
1076 // NOTE: Despite the fact that double-conversion's API is called
1077 // "DoubleToAscii", they actually use '0' (as opposed to u8'0').
1079 ensureCapacity(length
);
1080 for (int32_t i
= 0; i
< length
; i
++) {
1081 fBCD
.bcdBytes
.ptr
[i
] = buffer
[length
-i
-1] - '0';
1084 uint64_t result
= 0L;
1085 for (int32_t i
= 0; i
< length
; i
++) {
1086 result
|= static_cast<uint64_t>(buffer
[length
-i
-1] - '0') << (4 * i
);
1088 fBCD
.bcdLong
= result
;
1090 scale
= point
- length
;
1094 void DecimalQuantity::compact() {
1097 for (; delta
< precision
&& fBCD
.bcdBytes
.ptr
[delta
] == 0; delta
++);
1098 if (delta
== precision
) {
1103 // Remove trailing zeros
1107 // Compute precision
1108 int32_t leading
= precision
- 1;
1109 for (; leading
>= 0 && fBCD
.bcdBytes
.ptr
[leading
] == 0; leading
--);
1110 precision
= leading
+ 1;
1112 // Switch storage mechanism if possible
1113 if (precision
<= 16) {
1118 if (fBCD
.bcdLong
== 0L) {
1124 // Compact the number (remove trailing zeros)
1125 // TODO: Use a more efficient algorithm here and below. There is a logarithmic one.
1127 for (; delta
< precision
&& getDigitPos(delta
) == 0; delta
++);
1128 fBCD
.bcdLong
>>= delta
* 4;
1131 // Compute precision
1132 int32_t leading
= precision
- 1;
1133 for (; leading
>= 0 && getDigitPos(leading
) == 0; leading
--);
1134 precision
= leading
+ 1;
1138 void DecimalQuantity::ensureCapacity() {
1142 void DecimalQuantity::ensureCapacity(int32_t capacity
) {
1143 if (capacity
== 0) { return; }
1144 int32_t oldCapacity
= usingBytes
? fBCD
.bcdBytes
.len
: 0;
1146 // TODO: There is nothing being done to check for memory allocation failures.
1147 // TODO: Consider indexing by nybbles instead of bytes in C++, so that we can
1148 // make these arrays half the size.
1149 fBCD
.bcdBytes
.ptr
= static_cast<int8_t*>(uprv_malloc(capacity
* sizeof(int8_t)));
1150 fBCD
.bcdBytes
.len
= capacity
;
1151 // Initialize the byte array to zeros (this is done automatically in Java)
1152 uprv_memset(fBCD
.bcdBytes
.ptr
, 0, capacity
* sizeof(int8_t));
1153 } else if (oldCapacity
< capacity
) {
1154 auto bcd1
= static_cast<int8_t*>(uprv_malloc(capacity
* 2 * sizeof(int8_t)));
1155 uprv_memcpy(bcd1
, fBCD
.bcdBytes
.ptr
, oldCapacity
* sizeof(int8_t));
1156 // Initialize the rest of the byte array to zeros (this is done automatically in Java)
1157 uprv_memset(bcd1
+ oldCapacity
, 0, (capacity
- oldCapacity
) * sizeof(int8_t));
1158 uprv_free(fBCD
.bcdBytes
.ptr
);
1159 fBCD
.bcdBytes
.ptr
= bcd1
;
1160 fBCD
.bcdBytes
.len
= capacity
* 2;
1165 void DecimalQuantity::switchStorage() {
1167 // Change from bytes to long
1168 uint64_t bcdLong
= 0L;
1169 for (int i
= precision
- 1; i
>= 0; i
--) {
1171 bcdLong
|= fBCD
.bcdBytes
.ptr
[i
];
1173 uprv_free(fBCD
.bcdBytes
.ptr
);
1174 fBCD
.bcdBytes
.ptr
= nullptr;
1175 fBCD
.bcdLong
= bcdLong
;
1178 // Change from long to bytes
1179 // Copy the long into a local variable since it will get munged when we allocate the bytes
1180 uint64_t bcdLong
= fBCD
.bcdLong
;
1182 for (int i
= 0; i
< precision
; i
++) {
1183 fBCD
.bcdBytes
.ptr
[i
] = static_cast<int8_t>(bcdLong
& 0xf);
1186 U_ASSERT(usingBytes
);
1190 void DecimalQuantity::copyBcdFrom(const DecimalQuantity
&other
) {
1192 if (other
.usingBytes
) {
1193 ensureCapacity(other
.precision
);
1194 uprv_memcpy(fBCD
.bcdBytes
.ptr
, other
.fBCD
.bcdBytes
.ptr
, other
.precision
* sizeof(int8_t));
1196 fBCD
.bcdLong
= other
.fBCD
.bcdLong
;
1200 void DecimalQuantity::moveBcdFrom(DecimalQuantity
&other
) {
1202 if (other
.usingBytes
) {
1204 fBCD
.bcdBytes
.ptr
= other
.fBCD
.bcdBytes
.ptr
;
1205 fBCD
.bcdBytes
.len
= other
.fBCD
.bcdBytes
.len
;
1206 // Take ownership away from the old instance:
1207 other
.fBCD
.bcdBytes
.ptr
= nullptr;
1208 other
.usingBytes
= false;
1210 fBCD
.bcdLong
= other
.fBCD
.bcdLong
;
1214 const char16_t* DecimalQuantity::checkHealth() const {
1216 if (precision
== 0) { return u
"Zero precision but we are in byte mode"; }
1217 int32_t capacity
= fBCD
.bcdBytes
.len
;
1218 if (precision
> capacity
) { return u
"Precision exceeds length of byte array"; }
1219 if (getDigitPos(precision
- 1) == 0) { return u
"Most significant digit is zero in byte mode"; }
1220 if (getDigitPos(0) == 0) { return u
"Least significant digit is zero in long mode"; }
1221 for (int i
= 0; i
< precision
; i
++) {
1222 if (getDigitPos(i
) >= 10) { return u
"Digit exceeding 10 in byte array"; }
1223 if (getDigitPos(i
) < 0) { return u
"Digit below 0 in byte array"; }
1225 for (int i
= precision
; i
< capacity
; i
++) {
1226 if (getDigitPos(i
) != 0) { return u
"Nonzero digits outside of range in byte array"; }
1229 if (precision
== 0 && fBCD
.bcdLong
!= 0) {
1230 return u
"Value in bcdLong even though precision is zero";
1232 if (precision
> 16) { return u
"Precision exceeds length of long"; }
1233 if (precision
!= 0 && getDigitPos(precision
- 1) == 0) {
1234 return u
"Most significant digit is zero in long mode";
1236 if (precision
!= 0 && getDigitPos(0) == 0) {
1237 return u
"Least significant digit is zero in long mode";
1239 for (int i
= 0; i
< precision
; i
++) {
1240 if (getDigitPos(i
) >= 10) { return u
"Digit exceeding 10 in long"; }
1241 if (getDigitPos(i
) < 0) { return u
"Digit below 0 in long (?!)"; }
1243 for (int i
= precision
; i
< 16; i
++) {
1244 if (getDigitPos(i
) != 0) { return u
"Nonzero digits outside of range in long"; }
1252 bool DecimalQuantity::operator==(const DecimalQuantity
& other
) const {
1254 scale
== other
.scale
1255 && precision
== other
.precision
1256 && flags
== other
.flags
1257 && lReqPos
== other
.lReqPos
1258 && rReqPos
== other
.rReqPos
1259 && isApproximate
== other
.isApproximate
;
1264 if (precision
== 0) {
1266 } else if (isApproximate
) {
1267 return origDouble
== other
.origDouble
&& origDelta
== other
.origDelta
;
1269 for (int m
= getUpperDisplayMagnitude(); m
>= getLowerDisplayMagnitude(); m
--) {
1270 if (getDigit(m
) != other
.getDigit(m
)) {
1278 UnicodeString
DecimalQuantity::toString() const {
1279 MaybeStackArray
<char, 30> digits(precision
+ 1);
1280 for (int32_t i
= 0; i
< precision
; i
++) {
1281 digits
[i
] = getDigitPos(precision
- i
- 1) + '0';
1283 digits
[precision
] = 0; // terminate buffer
1288 "<DecimalQuantity %d:%d %s %s%s%s%d>",
1291 (usingBytes
? "bytes" : "long"),
1292 (isNegative() ? "-" : ""),
1293 (precision
== 0 ? "0" : digits
.getAlias()),
1296 return UnicodeString(buffer8
, -1, US_INV
);
1299 #endif /* #if !UCONFIG_NO_FORMATTING */