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
) {
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
) {
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 Signum
DecimalQuantity::signum() const {
324 } else if (isZeroish() && !isInfinite()) {
331 bool DecimalQuantity::isInfinite() const {
332 return (flags
& INFINITY_FLAG
) != 0;
335 bool DecimalQuantity::isNaN() const {
336 return (flags
& NAN_FLAG
) != 0;
339 bool DecimalQuantity::isZeroish() const {
340 return precision
== 0;
343 DecimalQuantity
&DecimalQuantity::setToInt(int32_t n
) {
346 if (n
== INT32_MIN
) {
347 flags
|= NEGATIVE_FLAG
;
348 // leave as INT32_MIN; handled below in _setToInt()
350 flags
|= NEGATIVE_FLAG
;
360 void DecimalQuantity::_setToInt(int32_t n
) {
361 if (n
== INT32_MIN
) {
362 readLongToBcd(-static_cast<int64_t>(n
));
368 DecimalQuantity
&DecimalQuantity::setToLong(int64_t n
) {
371 if (n
< 0 && n
> INT64_MIN
) {
372 flags
|= NEGATIVE_FLAG
;
382 void DecimalQuantity::_setToLong(int64_t n
) {
383 if (n
== INT64_MIN
) {
385 UErrorCode localStatus
= U_ZERO_ERROR
;
386 decnum
.setTo("9.223372036854775808E+18", localStatus
);
387 if (U_FAILURE(localStatus
)) { return; } // unexpected
388 flags
|= NEGATIVE_FLAG
;
389 readDecNumberToBcd(decnum
);
390 } else if (n
<= INT32_MAX
) {
391 readIntToBcd(static_cast<int32_t>(n
));
397 DecimalQuantity
&DecimalQuantity::setToDouble(double n
) {
400 // signbit() from <math.h> handles +0.0 vs -0.0
401 if (std::signbit(n
)) {
402 flags
|= NEGATIVE_FLAG
;
405 if (std::isnan(n
) != 0) {
407 } else if (std::isfinite(n
) == 0) {
408 flags
|= INFINITY_FLAG
;
416 void DecimalQuantity::_setToDoubleFast(double n
) {
417 isApproximate
= true;
421 // Make sure the double is an IEEE 754 double. If not, fall back to the slow path right now.
422 // TODO: Make a fast path for other types of doubles.
423 if (!std::numeric_limits
<double>::is_iec559
) {
424 convertToAccurateDouble();
425 // Turn off the approximate double flag, since the value is now exact.
426 isApproximate
= false;
431 // To get the bits from the double, use memcpy, which takes care of endianness.
433 uprv_memcpy(&ieeeBits
, &n
, sizeof(n
));
434 int32_t exponent
= static_cast<int32_t>((ieeeBits
& 0x7ff0000000000000L
) >> 52) - 0x3ff;
436 // Not all integers can be represented exactly for exponent > 52
437 if (exponent
<= 52 && static_cast<int64_t>(n
) == n
) {
438 _setToLong(static_cast<int64_t>(n
));
442 // 3.3219... is log2(10)
443 auto fracLength
= static_cast<int32_t> ((52 - exponent
) / 3.32192809489);
444 if (fracLength
>= 0) {
445 int32_t i
= fracLength
;
446 // 1e22 is the largest exact double.
447 for (; i
>= 22; i
-= 22) n
*= 1e22
;
448 n
*= DOUBLE_MULTIPLIERS
[i
];
450 int32_t i
= fracLength
;
451 // 1e22 is the largest exact double.
452 for (; i
<= -22; i
+= 22) n
/= 1e22
;
453 n
/= DOUBLE_MULTIPLIERS
[-i
];
455 auto result
= static_cast<int64_t>(std::round(n
));
462 void DecimalQuantity::convertToAccurateDouble() {
463 U_ASSERT(origDouble
!= 0);
464 int32_t delta
= origDelta
;
466 // Call the slow oracle function (Double.toString in Java, DoubleToAscii in C++).
467 char buffer
[DoubleToStringConverter::kBase10MaximalLength
+ 1];
468 bool sign
; // unused; always positive
471 DoubleToStringConverter::DoubleToAscii(
473 DoubleToStringConverter::DtoaMode::SHORTEST
,
483 readDoubleConversionToBcd(buffer
, length
, point
);
485 explicitExactDouble
= true;
488 DecimalQuantity
&DecimalQuantity::setToDecNumber(StringPiece n
, UErrorCode
& status
) {
492 // Compute the decNumber representation
494 decnum
.setTo(n
, status
);
496 _setToDecNum(decnum
, status
);
500 DecimalQuantity
& DecimalQuantity::setToDecNum(const DecNum
& decnum
, UErrorCode
& status
) {
504 _setToDecNum(decnum
, status
);
508 void DecimalQuantity::_setToDecNum(const DecNum
& decnum
, UErrorCode
& status
) {
509 if (U_FAILURE(status
)) { return; }
510 if (decnum
.isNegative()) {
511 flags
|= NEGATIVE_FLAG
;
513 if (!decnum
.isZero()) {
514 readDecNumberToBcd(decnum
);
519 int64_t DecimalQuantity::toLong(bool truncateIfOverflow
) const {
520 // NOTE: Call sites should be guarded by fitsInLong(), like this:
521 // if (dq.fitsInLong()) { /* use dq.toLong() */ } else { /* use some fallback */ }
522 // Fallback behavior upon truncateIfOverflow is to truncate at 17 digits.
523 uint64_t result
= 0L;
524 int32_t upperMagnitude
= scale
+ precision
- 1;
525 if (truncateIfOverflow
) {
526 upperMagnitude
= std::min(upperMagnitude
, 17);
528 for (int32_t magnitude
= upperMagnitude
; magnitude
>= 0; magnitude
--) {
529 result
= result
* 10 + getDigitPos(magnitude
- scale
);
532 return static_cast<int64_t>(0LL - result
); // i.e., -result
534 return static_cast<int64_t>(result
);
537 uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros
) const {
538 uint64_t result
= 0L;
539 int32_t magnitude
= -1;
540 int32_t lowerMagnitude
= scale
;
541 if (includeTrailingZeros
) {
542 lowerMagnitude
= std::min(lowerMagnitude
, rReqPos
);
544 for (; magnitude
>= lowerMagnitude
&& result
<= 1e18L
; magnitude
--) {
545 result
= result
* 10 + getDigitPos(magnitude
- scale
);
547 // Remove trailing zeros; this can happen during integer overflow cases.
548 if (!includeTrailingZeros
) {
549 while (result
> 0 && (result
% 10) == 0) {
556 bool DecimalQuantity::fitsInLong(bool ignoreFraction
) const {
557 if (isInfinite() || isNaN()) {
563 if (scale
< 0 && !ignoreFraction
) {
566 int magnitude
= getMagnitude();
567 if (magnitude
< 18) {
570 if (magnitude
> 18) {
573 // Hard case: the magnitude is 10^18.
574 // The largest int64 is: 9,223,372,036,854,775,807
575 for (int p
= 0; p
< precision
; p
++) {
576 int8_t digit
= getDigit(18 - p
);
577 static int8_t INT64_BCD
[] = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 };
578 if (digit
< INT64_BCD
[p
]) {
580 } else if (digit
> INT64_BCD
[p
]) {
584 // Exactly equal to max long plus one.
588 double DecimalQuantity::toDouble() const {
589 // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
590 // See the comment in the header file explaining the "isApproximate" field.
591 U_ASSERT(!isApproximate
);
595 } else if (isInfinite()) {
596 return isNegative() ? -INFINITY
: INFINITY
;
599 // We are processing well-formed input, so we don't need any special options to StringToDoubleConverter.
600 StringToDoubleConverter
converter(0, 0, 0, "", "");
601 UnicodeString numberString
= this->toScientificString();
603 return converter
.StringToDouble(
604 reinterpret_cast<const uint16_t*>(numberString
.getBuffer()),
605 numberString
.length(),
609 void DecimalQuantity::toDecNum(DecNum
& output
, UErrorCode
& status
) const {
610 // Special handling for zero
611 if (precision
== 0) {
612 output
.setTo("0", status
);
615 // Use the BCD constructor. We need to do a little bit of work to convert, though.
616 // The decNumber constructor expects most-significant first, but we store least-significant first.
617 MaybeStackArray
<uint8_t, 20> ubcd(precision
);
618 for (int32_t m
= 0; m
< precision
; m
++) {
619 ubcd
[precision
- m
- 1] = static_cast<uint8_t>(getDigitPos(m
));
621 output
.setTo(ubcd
.getAlias(), precision
, scale
, isNegative(), status
);
624 void DecimalQuantity::truncate() {
632 void DecimalQuantity::roundToNickel(int32_t magnitude
, RoundingMode roundingMode
, UErrorCode
& status
) {
633 roundToMagnitude(magnitude
, roundingMode
, true, status
);
636 void DecimalQuantity::roundToMagnitude(int32_t magnitude
, RoundingMode roundingMode
, UErrorCode
& status
) {
637 roundToMagnitude(magnitude
, roundingMode
, false, status
);
640 void DecimalQuantity::roundToMagnitude(int32_t magnitude
, RoundingMode roundingMode
, bool nickel
, UErrorCode
& status
) {
641 // The position in the BCD at which rounding will be performed; digits to the right of position
642 // will be rounded away.
643 int position
= safeSubtract(magnitude
, scale
);
645 // "trailing" = least significant digit to the left of rounding
646 int8_t trailingDigit
= getDigitPos(position
);
648 if (position
<= 0 && !isApproximate
&& (!nickel
|| trailingDigit
== 0 || trailingDigit
== 5)) {
649 // All digits are to the left of the rounding magnitude.
650 } else if (precision
== 0) {
651 // No rounding for zero.
653 // Perform rounding logic.
654 // "leading" = most significant digit to the right of rounding
655 int8_t leadingDigit
= getDigitPos(safeSubtract(position
, 1));
657 // Compute which section of the number we are in.
658 // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles)
659 // LOWER means we are between the bottom edge and the midpoint, like 1.391
660 // MIDPOINT means we are exactly in the middle, like 1.500
661 // UPPER means we are between the midpoint and the top edge, like 1.916
662 roundingutils::Section section
;
663 if (!isApproximate
) {
664 if (nickel
&& trailingDigit
!= 2 && trailingDigit
!= 7) {
665 // Nickel rounding, and not at .02x or .07x
666 if (trailingDigit
< 2) {
667 // .00, .01 => down to .00
668 section
= roundingutils::SECTION_LOWER
;
669 } else if (trailingDigit
< 5) {
670 // .03, .04 => up to .05
671 section
= roundingutils::SECTION_UPPER
;
672 } else if (trailingDigit
< 7) {
673 // .05, .06 => down to .05
674 section
= roundingutils::SECTION_LOWER
;
676 // .08, .09 => up to .10
677 section
= roundingutils::SECTION_UPPER
;
679 } else if (leadingDigit
< 5) {
680 // Includes nickel rounding .020-.024 and .070-.074
681 section
= roundingutils::SECTION_LOWER
;
682 } else if (leadingDigit
> 5) {
683 // Includes nickel rounding .026-.029 and .076-.079
684 section
= roundingutils::SECTION_UPPER
;
686 // Includes nickel rounding .025 and .075
687 section
= roundingutils::SECTION_MIDPOINT
;
688 for (int p
= safeSubtract(position
, 2); p
>= 0; p
--) {
689 if (getDigitPos(p
) != 0) {
690 section
= roundingutils::SECTION_UPPER
;
696 int32_t p
= safeSubtract(position
, 2);
697 int32_t minP
= uprv_max(0, precision
- 14);
698 if (leadingDigit
== 0 && (!nickel
|| trailingDigit
== 0 || trailingDigit
== 5)) {
699 section
= roundingutils::SECTION_LOWER_EDGE
;
700 for (; p
>= minP
; p
--) {
701 if (getDigitPos(p
) != 0) {
702 section
= roundingutils::SECTION_LOWER
;
706 } else if (leadingDigit
== 4 && (!nickel
|| trailingDigit
== 2 || trailingDigit
== 7)) {
707 section
= roundingutils::SECTION_MIDPOINT
;
708 for (; p
>= minP
; p
--) {
709 if (getDigitPos(p
) != 9) {
710 section
= roundingutils::SECTION_LOWER
;
714 } else if (leadingDigit
== 5 && (!nickel
|| trailingDigit
== 2 || trailingDigit
== 7)) {
715 section
= roundingutils::SECTION_MIDPOINT
;
716 for (; p
>= minP
; p
--) {
717 if (getDigitPos(p
) != 0) {
718 section
= roundingutils::SECTION_UPPER
;
722 } else if (leadingDigit
== 9 && (!nickel
|| trailingDigit
== 4 || trailingDigit
== 9)) {
723 section
= roundingutils::SECTION_UPPER_EDGE
;
724 for (; p
>= minP
; p
--) {
725 if (getDigitPos(p
) != 9) {
726 section
= roundingutils::SECTION_UPPER
;
730 } else if (nickel
&& trailingDigit
!= 2 && trailingDigit
!= 7) {
731 // Nickel rounding, and not at .02x or .07x
732 if (trailingDigit
< 2) {
733 // .00, .01 => down to .00
734 section
= roundingutils::SECTION_LOWER
;
735 } else if (trailingDigit
< 5) {
736 // .03, .04 => up to .05
737 section
= roundingutils::SECTION_UPPER
;
738 } else if (trailingDigit
< 7) {
739 // .05, .06 => down to .05
740 section
= roundingutils::SECTION_LOWER
;
742 // .08, .09 => up to .10
743 section
= roundingutils::SECTION_UPPER
;
745 } else if (leadingDigit
< 5) {
746 // Includes nickel rounding .020-.024 and .070-.074
747 section
= roundingutils::SECTION_LOWER
;
749 // Includes nickel rounding .026-.029 and .076-.079
750 section
= roundingutils::SECTION_UPPER
;
753 bool roundsAtMidpoint
= roundingutils::roundsAtMidpoint(roundingMode
);
754 if (safeSubtract(position
, 1) < precision
- 14 ||
755 (roundsAtMidpoint
&& section
== roundingutils::SECTION_MIDPOINT
) ||
756 (!roundsAtMidpoint
&& section
< 0 /* i.e. at upper or lower edge */)) {
757 // Oops! This means that we have to get the exact representation of the double,
758 // because the zone of uncertainty is along the rounding boundary.
759 convertToAccurateDouble();
760 roundToMagnitude(magnitude
, roundingMode
, nickel
, status
); // start over
764 // Turn off the approximate double flag, since the value is now confirmed to be exact.
765 isApproximate
= false;
769 if (position
<= 0 && (!nickel
|| trailingDigit
== 0 || trailingDigit
== 5)) {
770 // All digits are to the left of the rounding magnitude.
774 // Good to continue rounding.
775 if (section
== -1) { section
= roundingutils::SECTION_LOWER
; }
776 if (section
== -2) { section
= roundingutils::SECTION_UPPER
; }
779 // Nickel rounding "half even" goes to the nearest whole (away from the 5).
781 ? (trailingDigit
< 2 || trailingDigit
> 7
782 || (trailingDigit
== 2 && section
!= roundingutils::SECTION_UPPER
)
783 || (trailingDigit
== 7 && section
== roundingutils::SECTION_UPPER
))
784 : (trailingDigit
% 2) == 0;
786 bool roundDown
= roundingutils::getRoundingDirection(isEven
,
791 if (U_FAILURE(status
)) {
795 // Perform truncation
796 if (position
>= precision
) {
800 shiftRight(position
);
804 if (trailingDigit
< 5 && roundDown
) {
808 } else if (trailingDigit
>= 5 && !roundDown
) {
811 // do not return: use the bubbling logic below
814 // compact not necessary: digit at position 0 is nonzero
819 // Bubble the result to the higher digits
821 if (trailingDigit
== 9) {
823 // Note: in the long implementation, the most digits BCD can have at this point is
824 // 15, so bubblePos <= 15 and getDigitPos(bubblePos) is safe.
825 for (; getDigitPos(bubblePos
) == 9; bubblePos
++) {}
826 shiftRight(bubblePos
); // shift off the trailing 9s
828 int8_t digit0
= getDigitPos(0);
829 U_ASSERT(digit0
!= 9);
830 setDigitPos(0, static_cast<int8_t>(digit0
+ 1));
831 precision
+= 1; // in case an extra digit got added
838 void DecimalQuantity::roundToInfinity() {
840 convertToAccurateDouble();
844 void DecimalQuantity::appendDigit(int8_t value
, int32_t leadingZeros
, bool appendAsInteger
) {
845 U_ASSERT(leadingZeros
>= 0);
847 // Zero requires special handling to maintain the invariant that the least-significant digit
848 // in the BCD is nonzero.
850 if (appendAsInteger
&& precision
!= 0) {
851 scale
+= leadingZeros
+ 1;
856 // Deal with trailing zeros
858 leadingZeros
+= scale
;
859 if (appendAsInteger
) {
865 shiftLeft(leadingZeros
+ 1);
866 setDigitPos(0, value
);
868 // Fix scale if in integer mode
869 if (appendAsInteger
) {
870 scale
+= leadingZeros
+ 1;
874 UnicodeString
DecimalQuantity::toPlainString() const {
875 U_ASSERT(!isApproximate
);
880 if (precision
== 0 || getMagnitude() < 0) {
883 for (int m
= getUpperDisplayMagnitude(); m
>= getLowerDisplayMagnitude(); m
--) {
884 if (m
== -1) { sb
.append(u
'.'); }
885 sb
.append(getDigit(m
) + u
'0');
890 UnicodeString
DecimalQuantity::toScientificString() const {
891 U_ASSERT(!isApproximate
);
892 UnicodeString result
;
896 if (precision
== 0) {
897 result
.append(u
"0E+0", -1);
900 int32_t upperPos
= precision
- 1;
901 int32_t lowerPos
= 0;
902 int32_t p
= upperPos
;
903 result
.append(u
'0' + getDigitPos(p
));
904 if ((--p
) >= lowerPos
) {
906 for (; p
>= lowerPos
; p
--) {
907 result
.append(u
'0' + getDigitPos(p
));
911 int32_t _scale
= upperPos
+ scale
;
912 if (_scale
== INT32_MIN
) {
913 result
.append({u
"-2147483648", -1});
915 } else if (_scale
< 0) {
924 int32_t insertIndex
= result
.length();
926 std::div_t res
= std::div(_scale
, 10);
927 result
.insert(insertIndex
, u
'0' + res
.rem
);
933 ////////////////////////////////////////////////////
934 /// End of DecimalQuantity_AbstractBCD.java ///
935 /// Start of DecimalQuantity_DualStorageBCD.java ///
936 ////////////////////////////////////////////////////
938 int8_t DecimalQuantity::getDigitPos(int32_t position
) const {
940 if (position
< 0 || position
>= precision
) { return 0; }
941 return fBCD
.bcdBytes
.ptr
[position
];
943 if (position
< 0 || position
>= 16) { return 0; }
944 return (int8_t) ((fBCD
.bcdLong
>> (position
* 4)) & 0xf);
948 void DecimalQuantity::setDigitPos(int32_t position
, int8_t value
) {
949 U_ASSERT(position
>= 0);
951 ensureCapacity(position
+ 1);
952 fBCD
.bcdBytes
.ptr
[position
] = value
;
953 } else if (position
>= 16) {
955 ensureCapacity(position
+ 1);
956 fBCD
.bcdBytes
.ptr
[position
] = value
;
958 int shift
= position
* 4;
959 fBCD
.bcdLong
= (fBCD
.bcdLong
& ~(0xfL
<< shift
)) | ((long) value
<< shift
);
963 void DecimalQuantity::shiftLeft(int32_t numDigits
) {
964 if (!usingBytes
&& precision
+ numDigits
> 16) {
968 ensureCapacity(precision
+ numDigits
);
969 int i
= precision
+ numDigits
- 1;
970 for (; i
>= numDigits
; i
--) {
971 fBCD
.bcdBytes
.ptr
[i
] = fBCD
.bcdBytes
.ptr
[i
- numDigits
];
973 for (; i
>= 0; i
--) {
974 fBCD
.bcdBytes
.ptr
[i
] = 0;
977 fBCD
.bcdLong
<<= (numDigits
* 4);
980 precision
+= numDigits
;
983 void DecimalQuantity::shiftRight(int32_t numDigits
) {
986 for (; i
< precision
- numDigits
; i
++) {
987 fBCD
.bcdBytes
.ptr
[i
] = fBCD
.bcdBytes
.ptr
[i
+ numDigits
];
989 for (; i
< precision
; i
++) {
990 fBCD
.bcdBytes
.ptr
[i
] = 0;
993 fBCD
.bcdLong
>>= (numDigits
* 4);
996 precision
-= numDigits
;
999 void DecimalQuantity::popFromLeft(int32_t numDigits
) {
1000 U_ASSERT(numDigits
<= precision
);
1002 int i
= precision
- 1;
1003 for (; i
>= precision
- numDigits
; i
--) {
1004 fBCD
.bcdBytes
.ptr
[i
] = 0;
1007 fBCD
.bcdLong
&= (static_cast<uint64_t>(1) << ((precision
- numDigits
) * 4)) - 1;
1009 precision
-= numDigits
;
1012 void DecimalQuantity::setBcdToZero() {
1014 uprv_free(fBCD
.bcdBytes
.ptr
);
1015 fBCD
.bcdBytes
.ptr
= nullptr;
1021 isApproximate
= false;
1026 void DecimalQuantity::readIntToBcd(int32_t n
) {
1028 // ints always fit inside the long implementation.
1029 uint64_t result
= 0L;
1031 for (; n
!= 0; n
/= 10, i
--) {
1032 result
= (result
>> 4) + ((static_cast<uint64_t>(n
) % 10) << 60);
1034 U_ASSERT(!usingBytes
);
1035 fBCD
.bcdLong
= result
>> (i
* 4);
1040 void DecimalQuantity::readLongToBcd(int64_t n
) {
1042 if (n
>= 10000000000000000L) {
1045 for (; n
!= 0L; n
/= 10L, i
++) {
1046 fBCD
.bcdBytes
.ptr
[i
] = static_cast<int8_t>(n
% 10);
1048 U_ASSERT(usingBytes
);
1052 uint64_t result
= 0L;
1054 for (; n
!= 0L; n
/= 10L, i
--) {
1055 result
= (result
>> 4) + ((n
% 10) << 60);
1058 U_ASSERT(!usingBytes
);
1059 fBCD
.bcdLong
= result
>> (i
* 4);
1065 void DecimalQuantity::readDecNumberToBcd(const DecNum
& decnum
) {
1066 const decNumber
* dn
= decnum
.getRawDecNumber();
1067 if (dn
->digits
> 16) {
1068 ensureCapacity(dn
->digits
);
1069 for (int32_t i
= 0; i
< dn
->digits
; i
++) {
1070 fBCD
.bcdBytes
.ptr
[i
] = dn
->lsu
[i
];
1073 uint64_t result
= 0L;
1074 for (int32_t i
= 0; i
< dn
->digits
; i
++) {
1075 result
|= static_cast<uint64_t>(dn
->lsu
[i
]) << (4 * i
);
1077 fBCD
.bcdLong
= result
;
1079 scale
= dn
->exponent
;
1080 precision
= dn
->digits
;
1083 void DecimalQuantity::readDoubleConversionToBcd(
1084 const char* buffer
, int32_t length
, int32_t point
) {
1085 // NOTE: Despite the fact that double-conversion's API is called
1086 // "DoubleToAscii", they actually use '0' (as opposed to u8'0').
1088 ensureCapacity(length
);
1089 for (int32_t i
= 0; i
< length
; i
++) {
1090 fBCD
.bcdBytes
.ptr
[i
] = buffer
[length
-i
-1] - '0';
1093 uint64_t result
= 0L;
1094 for (int32_t i
= 0; i
< length
; i
++) {
1095 result
|= static_cast<uint64_t>(buffer
[length
-i
-1] - '0') << (4 * i
);
1097 fBCD
.bcdLong
= result
;
1099 scale
= point
- length
;
1103 void DecimalQuantity::compact() {
1106 for (; delta
< precision
&& fBCD
.bcdBytes
.ptr
[delta
] == 0; delta
++);
1107 if (delta
== precision
) {
1112 // Remove trailing zeros
1116 // Compute precision
1117 int32_t leading
= precision
- 1;
1118 for (; leading
>= 0 && fBCD
.bcdBytes
.ptr
[leading
] == 0; leading
--);
1119 precision
= leading
+ 1;
1121 // Switch storage mechanism if possible
1122 if (precision
<= 16) {
1127 if (fBCD
.bcdLong
== 0L) {
1133 // Compact the number (remove trailing zeros)
1134 // TODO: Use a more efficient algorithm here and below. There is a logarithmic one.
1136 for (; delta
< precision
&& getDigitPos(delta
) == 0; delta
++);
1137 fBCD
.bcdLong
>>= delta
* 4;
1140 // Compute precision
1141 int32_t leading
= precision
- 1;
1142 for (; leading
>= 0 && getDigitPos(leading
) == 0; leading
--);
1143 precision
= leading
+ 1;
1147 void DecimalQuantity::ensureCapacity() {
1151 void DecimalQuantity::ensureCapacity(int32_t capacity
) {
1152 if (capacity
== 0) { return; }
1153 int32_t oldCapacity
= usingBytes
? fBCD
.bcdBytes
.len
: 0;
1155 // TODO: There is nothing being done to check for memory allocation failures.
1156 // TODO: Consider indexing by nybbles instead of bytes in C++, so that we can
1157 // make these arrays half the size.
1158 fBCD
.bcdBytes
.ptr
= static_cast<int8_t*>(uprv_malloc(capacity
* sizeof(int8_t)));
1159 fBCD
.bcdBytes
.len
= capacity
;
1160 // Initialize the byte array to zeros (this is done automatically in Java)
1161 uprv_memset(fBCD
.bcdBytes
.ptr
, 0, capacity
* sizeof(int8_t));
1162 } else if (oldCapacity
< capacity
) {
1163 auto bcd1
= static_cast<int8_t*>(uprv_malloc(capacity
* 2 * sizeof(int8_t)));
1164 uprv_memcpy(bcd1
, fBCD
.bcdBytes
.ptr
, oldCapacity
* sizeof(int8_t));
1165 // Initialize the rest of the byte array to zeros (this is done automatically in Java)
1166 uprv_memset(bcd1
+ oldCapacity
, 0, (capacity
- oldCapacity
) * sizeof(int8_t));
1167 uprv_free(fBCD
.bcdBytes
.ptr
);
1168 fBCD
.bcdBytes
.ptr
= bcd1
;
1169 fBCD
.bcdBytes
.len
= capacity
* 2;
1174 void DecimalQuantity::switchStorage() {
1176 // Change from bytes to long
1177 uint64_t bcdLong
= 0L;
1178 for (int i
= precision
- 1; i
>= 0; i
--) {
1180 bcdLong
|= fBCD
.bcdBytes
.ptr
[i
];
1182 uprv_free(fBCD
.bcdBytes
.ptr
);
1183 fBCD
.bcdBytes
.ptr
= nullptr;
1184 fBCD
.bcdLong
= bcdLong
;
1187 // Change from long to bytes
1188 // Copy the long into a local variable since it will get munged when we allocate the bytes
1189 uint64_t bcdLong
= fBCD
.bcdLong
;
1191 for (int i
= 0; i
< precision
; i
++) {
1192 fBCD
.bcdBytes
.ptr
[i
] = static_cast<int8_t>(bcdLong
& 0xf);
1195 U_ASSERT(usingBytes
);
1199 void DecimalQuantity::copyBcdFrom(const DecimalQuantity
&other
) {
1201 if (other
.usingBytes
) {
1202 ensureCapacity(other
.precision
);
1203 uprv_memcpy(fBCD
.bcdBytes
.ptr
, other
.fBCD
.bcdBytes
.ptr
, other
.precision
* sizeof(int8_t));
1205 fBCD
.bcdLong
= other
.fBCD
.bcdLong
;
1209 void DecimalQuantity::moveBcdFrom(DecimalQuantity
&other
) {
1211 if (other
.usingBytes
) {
1213 fBCD
.bcdBytes
.ptr
= other
.fBCD
.bcdBytes
.ptr
;
1214 fBCD
.bcdBytes
.len
= other
.fBCD
.bcdBytes
.len
;
1215 // Take ownership away from the old instance:
1216 other
.fBCD
.bcdBytes
.ptr
= nullptr;
1217 other
.usingBytes
= false;
1219 fBCD
.bcdLong
= other
.fBCD
.bcdLong
;
1223 const char16_t* DecimalQuantity::checkHealth() const {
1225 if (precision
== 0) { return u
"Zero precision but we are in byte mode"; }
1226 int32_t capacity
= fBCD
.bcdBytes
.len
;
1227 if (precision
> capacity
) { return u
"Precision exceeds length of byte array"; }
1228 if (getDigitPos(precision
- 1) == 0) { return u
"Most significant digit is zero in byte mode"; }
1229 if (getDigitPos(0) == 0) { return u
"Least significant digit is zero in long mode"; }
1230 for (int i
= 0; i
< precision
; i
++) {
1231 if (getDigitPos(i
) >= 10) { return u
"Digit exceeding 10 in byte array"; }
1232 if (getDigitPos(i
) < 0) { return u
"Digit below 0 in byte array"; }
1234 for (int i
= precision
; i
< capacity
; i
++) {
1235 if (getDigitPos(i
) != 0) { return u
"Nonzero digits outside of range in byte array"; }
1238 if (precision
== 0 && fBCD
.bcdLong
!= 0) {
1239 return u
"Value in bcdLong even though precision is zero";
1241 if (precision
> 16) { return u
"Precision exceeds length of long"; }
1242 if (precision
!= 0 && getDigitPos(precision
- 1) == 0) {
1243 return u
"Most significant digit is zero in long mode";
1245 if (precision
!= 0 && getDigitPos(0) == 0) {
1246 return u
"Least significant digit is zero in long mode";
1248 for (int i
= 0; i
< precision
; i
++) {
1249 if (getDigitPos(i
) >= 10) { return u
"Digit exceeding 10 in long"; }
1250 if (getDigitPos(i
) < 0) { return u
"Digit below 0 in long (?!)"; }
1252 for (int i
= precision
; i
< 16; i
++) {
1253 if (getDigitPos(i
) != 0) { return u
"Nonzero digits outside of range in long"; }
1261 bool DecimalQuantity::operator==(const DecimalQuantity
& other
) const {
1263 scale
== other
.scale
1264 && precision
== other
.precision
1265 && flags
== other
.flags
1266 && lReqPos
== other
.lReqPos
1267 && rReqPos
== other
.rReqPos
1268 && isApproximate
== other
.isApproximate
;
1273 if (precision
== 0) {
1275 } else if (isApproximate
) {
1276 return origDouble
== other
.origDouble
&& origDelta
== other
.origDelta
;
1278 for (int m
= getUpperDisplayMagnitude(); m
>= getLowerDisplayMagnitude(); m
--) {
1279 if (getDigit(m
) != other
.getDigit(m
)) {
1287 UnicodeString
DecimalQuantity::toString() const {
1288 MaybeStackArray
<char, 30> digits(precision
+ 1);
1289 for (int32_t i
= 0; i
< precision
; i
++) {
1290 digits
[i
] = getDigitPos(precision
- i
- 1) + '0';
1292 digits
[precision
] = 0; // terminate buffer
1297 "<DecimalQuantity %d:%d %s %s%s%s%d>",
1300 (usingBytes
? "bytes" : "long"),
1301 (isNegative() ? "-" : ""),
1302 (precision
== 0 ? "0" : digits
.getAlias()),
1305 return UnicodeString(buffer8
, -1, US_INV
);
1308 #endif /* #if !UCONFIG_NO_FORMATTING */