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 lOptPos
= other
.lOptPos
;
116 lReqPos
= other
.lReqPos
;
117 rReqPos
= other
.rReqPos
;
118 rOptPos
= other
.rOptPos
;
120 precision
= other
.precision
;
122 origDouble
= other
.origDouble
;
123 origDelta
= other
.origDelta
;
124 isApproximate
= other
.isApproximate
;
127 void DecimalQuantity::clear() {
133 setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data
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
);
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
) {
147 // Save values into internal state
148 // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
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
);
158 // Save values into internal state
159 // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
164 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);
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?
178 double temp
= toDouble();
179 temp
/= roundingIncrement
;
180 // Use another DecimalQuantity to perform the actual rounding...
182 dq
.setToDouble(temp
);
183 dq
.roundToMagnitude(0, roundingMode
, status
);
184 temp
= dq
.toDouble();
185 temp
*= roundingIncrement
;
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
);
193 void DecimalQuantity::multiplyBy(const DecNum
& multiplicand
, UErrorCode
& status
) {
194 if (isInfinite() || isZero() || isNaN()) {
197 // Convert to DecNum, multiply, and convert back.
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
);
206 void DecimalQuantity::divideBy(const DecNum
& divisor
, UErrorCode
& status
) {
207 if (isInfinite() || isZero() || isNaN()) {
210 // Convert to DecNum, multiply, and convert back.
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
);
219 void DecimalQuantity::negate() {
220 flags
^= NEGATIVE_FLAG
;
223 int32_t DecimalQuantity::getMagnitude() const {
224 U_ASSERT(precision
!= 0);
225 return scale
+ precision
- 1;
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
235 overflow
= overflow
|| uprv_add32_overflow(scale
, precision
, &dummy
);
241 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
);
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();
259 return std::abs(toDouble());
263 bool DecimalQuantity::hasIntegerValue() const {
267 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
);
272 int32_t magnitude
= scale
+ precision
;
273 int32_t result
= (lReqPos
> magnitude
) ? lReqPos
: (lOptPos
< magnitude
) ? lOptPos
: magnitude
;
277 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
);
282 int32_t magnitude
= scale
;
283 int32_t result
= (rReqPos
< magnitude
) ? rReqPos
: (rOptPos
> magnitude
) ? rOptPos
: magnitude
;
287 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
);
292 return getDigitPos(magnitude
- scale
);
295 int32_t DecimalQuantity::fractionCount() const {
296 return -getLowerDisplayMagnitude();
299 int32_t DecimalQuantity::fractionCountWithoutTrailingZeros() const {
300 return -scale
> 0 ? -scale
: 0; // max(-scale, 0)
303 bool DecimalQuantity::isNegative() const {
304 return (flags
& NEGATIVE_FLAG
) != 0;
307 int8_t DecimalQuantity::signum() const {
308 return isNegative() ? -1 : isZero() ? 0 : 1;
311 bool DecimalQuantity::isInfinite() const {
312 return (flags
& INFINITY_FLAG
) != 0;
315 bool DecimalQuantity::isNaN() const {
316 return (flags
& NAN_FLAG
) != 0;
319 bool DecimalQuantity::isZero() const {
320 return precision
== 0;
323 DecimalQuantity
&DecimalQuantity::setToInt(int32_t n
) {
326 if (n
== INT32_MIN
) {
327 flags
|= NEGATIVE_FLAG
;
328 // leave as INT32_MIN; handled below in _setToInt()
330 flags
|= NEGATIVE_FLAG
;
340 void DecimalQuantity::_setToInt(int32_t n
) {
341 if (n
== INT32_MIN
) {
342 readLongToBcd(-static_cast<int64_t>(n
));
348 DecimalQuantity
&DecimalQuantity::setToLong(int64_t n
) {
351 if (n
< 0 && n
> INT64_MIN
) {
352 flags
|= NEGATIVE_FLAG
;
362 void DecimalQuantity::_setToLong(int64_t n
) {
363 if (n
== INT64_MIN
) {
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
));
377 DecimalQuantity
&DecimalQuantity::setToDouble(double n
) {
380 // signbit() from <math.h> handles +0.0 vs -0.0
381 if (std::signbit(n
)) {
382 flags
|= NEGATIVE_FLAG
;
385 if (std::isnan(n
) != 0) {
387 } else if (std::isfinite(n
) == 0) {
388 flags
|= INFINITY_FLAG
;
396 void DecimalQuantity::_setToDoubleFast(double n
) {
397 isApproximate
= true;
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;
411 // To get the bits from the double, use memcpy, which takes care of endianness.
413 uprv_memcpy(&ieeeBits
, &n
, sizeof(n
));
414 int32_t exponent
= static_cast<int32_t>((ieeeBits
& 0x7ff0000000000000L
) >> 52) - 0x3ff;
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
));
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
];
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
];
435 auto result
= static_cast<int64_t>(std::round(n
));
442 void DecimalQuantity::convertToAccurateDouble() {
443 U_ASSERT(origDouble
!= 0);
444 int32_t delta
= origDelta
;
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
451 DoubleToStringConverter::DoubleToAscii(
453 DoubleToStringConverter::DtoaMode::SHORTEST
,
463 readDoubleConversionToBcd(buffer
, length
, point
);
465 explicitExactDouble
= true;
468 DecimalQuantity
&DecimalQuantity::setToDecNumber(StringPiece n
, UErrorCode
& status
) {
472 // Compute the decNumber representation
474 decnum
.setTo(n
, status
);
476 _setToDecNum(decnum
, status
);
480 DecimalQuantity
& DecimalQuantity::setToDecNum(const DecNum
& decnum
, UErrorCode
& status
) {
484 _setToDecNum(decnum
, status
);
488 void DecimalQuantity::_setToDecNum(const DecNum
& decnum
, UErrorCode
& status
) {
489 if (U_FAILURE(status
)) { return; }
490 if (decnum
.isNegative()) {
491 flags
|= NEGATIVE_FLAG
;
493 if (!decnum
.isZero()) {
494 readDecNumberToBcd(decnum
);
499 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);
508 for (int32_t magnitude
= upperMagnitude
; magnitude
>= 0; magnitude
--) {
509 result
= result
* 10 + getDigitPos(magnitude
- scale
);
512 return static_cast<int64_t>(0LL - result
); // i.e., -result
514 return static_cast<int64_t>(result
);
517 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
);
524 for (; magnitude
>= lowerMagnitude
&& result
<= 1e18L
; magnitude
--) {
525 result
= result
* 10 + getDigitPos(magnitude
- scale
);
527 // Remove trailing zeros; this can happen during integer overflow cases.
528 if (!includeTrailingZeros
) {
529 while (result
> 0 && (result
% 10) == 0) {
536 bool DecimalQuantity::fitsInLong(bool ignoreFraction
) const {
540 if (scale
< 0 && !ignoreFraction
) {
543 int magnitude
= getMagnitude();
544 if (magnitude
< 18) {
547 if (magnitude
> 18) {
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
]) {
557 } else if (digit
> INT64_BCD
[p
]) {
561 // Exactly equal to max long plus one.
565 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
);
572 } else if (isInfinite()) {
573 return isNegative() ? -INFINITY
: INFINITY
;
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();
580 return converter
.StringToDouble(
581 reinterpret_cast<const uint16_t*>(numberString
.getBuffer()),
582 numberString
.length(),
586 void DecimalQuantity::toDecNum(DecNum
& output
, UErrorCode
& status
) const {
587 // Special handling for zero
588 if (precision
== 0) {
589 output
.setTo("0", status
);
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
));
598 output
.setTo(ubcd
.getAlias(), precision
, scale
, isNegative(), status
);
601 void DecimalQuantity::truncate() {
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
);
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.
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
);
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
;
639 for (int p
= safeSubtract(position
, 2); p
>= 0; p
--) {
640 if (getDigitPos(p
) != 0) {
641 section
= roundingutils::SECTION_UPPER
;
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
;
657 } else if (leadingDigit
== 4) {
658 for (; p
>= minP
; p
--) {
659 if (getDigitPos(p
) != 9) {
660 section
= roundingutils::SECTION_LOWER
;
664 } else if (leadingDigit
== 5) {
665 for (; p
>= minP
; p
--) {
666 if (getDigitPos(p
) != 0) {
667 section
= roundingutils::SECTION_UPPER
;
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
;
679 } else if (leadingDigit
< 5) {
680 section
= roundingutils::SECTION_LOWER
;
682 section
= roundingutils::SECTION_UPPER
;
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
696 // Turn off the approximate double flag, since the value is now confirmed to be exact.
697 isApproximate
= false;
702 // All digits are to the left of the rounding magnitude.
706 // Good to continue rounding.
707 if (section
== -1) { section
= roundingutils::SECTION_LOWER
; }
708 if (section
== -2) { section
= roundingutils::SECTION_UPPER
; }
711 bool roundDown
= roundingutils::getRoundingDirection((trailingDigit
% 2) == 0,
716 if (U_FAILURE(status
)) {
720 // Perform truncation
721 if (position
>= precision
) {
725 shiftRight(position
);
728 // Bubble the result to the higher digits
730 if (trailingDigit
== 9) {
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
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
747 void DecimalQuantity::roundToInfinity() {
749 convertToAccurateDouble();
753 void DecimalQuantity::appendDigit(int8_t value
, int32_t leadingZeros
, bool appendAsInteger
) {
754 U_ASSERT(leadingZeros
>= 0);
756 // Zero requires special handling to maintain the invariant that the least-significant digit
757 // in the BCD is nonzero.
759 if (appendAsInteger
&& precision
!= 0) {
760 scale
+= leadingZeros
+ 1;
765 // Deal with trailing zeros
767 leadingZeros
+= scale
;
768 if (appendAsInteger
) {
774 shiftLeft(leadingZeros
+ 1);
775 setDigitPos(0, value
);
777 // Fix scale if in integer mode
778 if (appendAsInteger
) {
779 scale
+= leadingZeros
+ 1;
783 UnicodeString
DecimalQuantity::toPlainString() const {
784 U_ASSERT(!isApproximate
);
789 if (precision
== 0 || getMagnitude() < 0) {
792 for (int m
= getUpperDisplayMagnitude(); m
>= getLowerDisplayMagnitude(); m
--) {
793 if (m
== -1) { sb
.append(u
'.'); }
794 sb
.append(getDigit(m
) + u
'0');
799 UnicodeString
DecimalQuantity::toScientificString() const {
800 U_ASSERT(!isApproximate
);
801 UnicodeString result
;
805 if (precision
== 0) {
806 result
.append(u
"0E+0", -1);
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
) {
817 for (; p
>= lowerPos
; p
--) {
818 result
.append(u
'0' + getDigitPos(p
));
822 int32_t _scale
= upperPos
+ scale
;
832 int32_t insertIndex
= result
.length();
834 std::div_t res
= std::div(_scale
, 10);
835 result
.insert(insertIndex
, u
'0' + res
.rem
);
841 ////////////////////////////////////////////////////
842 /// End of DecimalQuantity_AbstractBCD.java ///
843 /// Start of DecimalQuantity_DualStorageBCD.java ///
844 ////////////////////////////////////////////////////
846 int8_t DecimalQuantity::getDigitPos(int32_t position
) const {
848 if (position
< 0 || position
>= precision
) { return 0; }
849 return fBCD
.bcdBytes
.ptr
[position
];
851 if (position
< 0 || position
>= 16) { return 0; }
852 return (int8_t) ((fBCD
.bcdLong
>> (position
* 4)) & 0xf);
856 void DecimalQuantity::setDigitPos(int32_t position
, int8_t value
) {
857 U_ASSERT(position
>= 0);
859 ensureCapacity(position
+ 1);
860 fBCD
.bcdBytes
.ptr
[position
] = value
;
861 } else if (position
>= 16) {
863 ensureCapacity(position
+ 1);
864 fBCD
.bcdBytes
.ptr
[position
] = value
;
866 int shift
= position
* 4;
867 fBCD
.bcdLong
= (fBCD
.bcdLong
& ~(0xfL
<< shift
)) | ((long) value
<< shift
);
871 void DecimalQuantity::shiftLeft(int32_t numDigits
) {
872 if (!usingBytes
&& precision
+ numDigits
> 16) {
876 ensureCapacity(precision
+ numDigits
);
877 int i
= precision
+ numDigits
- 1;
878 for (; i
>= numDigits
; i
--) {
879 fBCD
.bcdBytes
.ptr
[i
] = fBCD
.bcdBytes
.ptr
[i
- numDigits
];
881 for (; i
>= 0; i
--) {
882 fBCD
.bcdBytes
.ptr
[i
] = 0;
885 fBCD
.bcdLong
<<= (numDigits
* 4);
888 precision
+= numDigits
;
891 void DecimalQuantity::shiftRight(int32_t numDigits
) {
894 for (; i
< precision
- numDigits
; i
++) {
895 fBCD
.bcdBytes
.ptr
[i
] = fBCD
.bcdBytes
.ptr
[i
+ numDigits
];
897 for (; i
< precision
; i
++) {
898 fBCD
.bcdBytes
.ptr
[i
] = 0;
901 fBCD
.bcdLong
>>= (numDigits
* 4);
904 precision
-= numDigits
;
907 void DecimalQuantity::setBcdToZero() {
909 uprv_free(fBCD
.bcdBytes
.ptr
);
910 fBCD
.bcdBytes
.ptr
= nullptr;
916 isApproximate
= false;
921 void DecimalQuantity::readIntToBcd(int32_t n
) {
923 // ints always fit inside the long implementation.
924 uint64_t result
= 0L;
926 for (; n
!= 0; n
/= 10, i
--) {
927 result
= (result
>> 4) + ((static_cast<uint64_t>(n
) % 10) << 60);
929 U_ASSERT(!usingBytes
);
930 fBCD
.bcdLong
= result
>> (i
* 4);
935 void DecimalQuantity::readLongToBcd(int64_t n
) {
937 if (n
>= 10000000000000000L) {
940 for (; n
!= 0L; n
/= 10L, i
++) {
941 fBCD
.bcdBytes
.ptr
[i
] = static_cast<int8_t>(n
% 10);
943 U_ASSERT(usingBytes
);
947 uint64_t result
= 0L;
949 for (; n
!= 0L; n
/= 10L, i
--) {
950 result
= (result
>> 4) + ((n
% 10) << 60);
953 U_ASSERT(!usingBytes
);
954 fBCD
.bcdLong
= result
>> (i
* 4);
960 void DecimalQuantity::readDecNumberToBcd(const DecNum
& decnum
) {
961 const decNumber
* dn
= decnum
.getRawDecNumber();
962 if (dn
->digits
> 16) {
963 ensureCapacity(dn
->digits
);
964 for (int32_t i
= 0; i
< dn
->digits
; i
++) {
965 fBCD
.bcdBytes
.ptr
[i
] = dn
->lsu
[i
];
968 uint64_t result
= 0L;
969 for (int32_t i
= 0; i
< dn
->digits
; i
++) {
970 result
|= static_cast<uint64_t>(dn
->lsu
[i
]) << (4 * i
);
972 fBCD
.bcdLong
= result
;
974 scale
= dn
->exponent
;
975 precision
= dn
->digits
;
978 void DecimalQuantity::readDoubleConversionToBcd(
979 const char* buffer
, int32_t length
, int32_t point
) {
980 // NOTE: Despite the fact that double-conversion's API is called
981 // "DoubleToAscii", they actually use '0' (as opposed to u8'0').
983 ensureCapacity(length
);
984 for (int32_t i
= 0; i
< length
; i
++) {
985 fBCD
.bcdBytes
.ptr
[i
] = buffer
[length
-i
-1] - '0';
988 uint64_t result
= 0L;
989 for (int32_t i
= 0; i
< length
; i
++) {
990 result
|= static_cast<uint64_t>(buffer
[length
-i
-1] - '0') << (4 * i
);
992 fBCD
.bcdLong
= result
;
994 scale
= point
- length
;
998 void DecimalQuantity::compact() {
1001 for (; delta
< precision
&& fBCD
.bcdBytes
.ptr
[delta
] == 0; delta
++);
1002 if (delta
== precision
) {
1007 // Remove trailing zeros
1011 // Compute precision
1012 int32_t leading
= precision
- 1;
1013 for (; leading
>= 0 && fBCD
.bcdBytes
.ptr
[leading
] == 0; leading
--);
1014 precision
= leading
+ 1;
1016 // Switch storage mechanism if possible
1017 if (precision
<= 16) {
1022 if (fBCD
.bcdLong
== 0L) {
1028 // Compact the number (remove trailing zeros)
1029 // TODO: Use a more efficient algorithm here and below. There is a logarithmic one.
1031 for (; delta
< precision
&& getDigitPos(delta
) == 0; delta
++);
1032 fBCD
.bcdLong
>>= delta
* 4;
1035 // Compute precision
1036 int32_t leading
= precision
- 1;
1037 for (; leading
>= 0 && getDigitPos(leading
) == 0; leading
--);
1038 precision
= leading
+ 1;
1042 void DecimalQuantity::ensureCapacity() {
1046 void DecimalQuantity::ensureCapacity(int32_t capacity
) {
1047 if (capacity
== 0) { return; }
1048 int32_t oldCapacity
= usingBytes
? fBCD
.bcdBytes
.len
: 0;
1050 // TODO: There is nothing being done to check for memory allocation failures.
1051 // TODO: Consider indexing by nybbles instead of bytes in C++, so that we can
1052 // make these arrays half the size.
1053 fBCD
.bcdBytes
.ptr
= static_cast<int8_t*>(uprv_malloc(capacity
* sizeof(int8_t)));
1054 fBCD
.bcdBytes
.len
= capacity
;
1055 // Initialize the byte array to zeros (this is done automatically in Java)
1056 uprv_memset(fBCD
.bcdBytes
.ptr
, 0, capacity
* sizeof(int8_t));
1057 } else if (oldCapacity
< capacity
) {
1058 auto bcd1
= static_cast<int8_t*>(uprv_malloc(capacity
* 2 * sizeof(int8_t)));
1059 uprv_memcpy(bcd1
, fBCD
.bcdBytes
.ptr
, oldCapacity
* sizeof(int8_t));
1060 // Initialize the rest of the byte array to zeros (this is done automatically in Java)
1061 uprv_memset(bcd1
+ oldCapacity
, 0, (capacity
- oldCapacity
) * sizeof(int8_t));
1062 uprv_free(fBCD
.bcdBytes
.ptr
);
1063 fBCD
.bcdBytes
.ptr
= bcd1
;
1064 fBCD
.bcdBytes
.len
= capacity
* 2;
1069 void DecimalQuantity::switchStorage() {
1071 // Change from bytes to long
1072 uint64_t bcdLong
= 0L;
1073 for (int i
= precision
- 1; i
>= 0; i
--) {
1075 bcdLong
|= fBCD
.bcdBytes
.ptr
[i
];
1077 uprv_free(fBCD
.bcdBytes
.ptr
);
1078 fBCD
.bcdBytes
.ptr
= nullptr;
1079 fBCD
.bcdLong
= bcdLong
;
1082 // Change from long to bytes
1083 // Copy the long into a local variable since it will get munged when we allocate the bytes
1084 uint64_t bcdLong
= fBCD
.bcdLong
;
1086 for (int i
= 0; i
< precision
; i
++) {
1087 fBCD
.bcdBytes
.ptr
[i
] = static_cast<int8_t>(bcdLong
& 0xf);
1090 U_ASSERT(usingBytes
);
1094 void DecimalQuantity::copyBcdFrom(const DecimalQuantity
&other
) {
1096 if (other
.usingBytes
) {
1097 ensureCapacity(other
.precision
);
1098 uprv_memcpy(fBCD
.bcdBytes
.ptr
, other
.fBCD
.bcdBytes
.ptr
, other
.precision
* sizeof(int8_t));
1100 fBCD
.bcdLong
= other
.fBCD
.bcdLong
;
1104 void DecimalQuantity::moveBcdFrom(DecimalQuantity
&other
) {
1106 if (other
.usingBytes
) {
1108 fBCD
.bcdBytes
.ptr
= other
.fBCD
.bcdBytes
.ptr
;
1109 fBCD
.bcdBytes
.len
= other
.fBCD
.bcdBytes
.len
;
1110 // Take ownership away from the old instance:
1111 other
.fBCD
.bcdBytes
.ptr
= nullptr;
1112 other
.usingBytes
= false;
1114 fBCD
.bcdLong
= other
.fBCD
.bcdLong
;
1118 const char16_t* DecimalQuantity::checkHealth() const {
1120 if (precision
== 0) { return u
"Zero precision but we are in byte mode"; }
1121 int32_t capacity
= fBCD
.bcdBytes
.len
;
1122 if (precision
> capacity
) { return u
"Precision exceeds length of byte array"; }
1123 if (getDigitPos(precision
- 1) == 0) { return u
"Most significant digit is zero in byte mode"; }
1124 if (getDigitPos(0) == 0) { return u
"Least significant digit is zero in long mode"; }
1125 for (int i
= 0; i
< precision
; i
++) {
1126 if (getDigitPos(i
) >= 10) { return u
"Digit exceeding 10 in byte array"; }
1127 if (getDigitPos(i
) < 0) { return u
"Digit below 0 in byte array"; }
1129 for (int i
= precision
; i
< capacity
; i
++) {
1130 if (getDigitPos(i
) != 0) { return u
"Nonzero digits outside of range in byte array"; }
1133 if (precision
== 0 && fBCD
.bcdLong
!= 0) {
1134 return u
"Value in bcdLong even though precision is zero";
1136 if (precision
> 16) { return u
"Precision exceeds length of long"; }
1137 if (precision
!= 0 && getDigitPos(precision
- 1) == 0) {
1138 return u
"Most significant digit is zero in long mode";
1140 if (precision
!= 0 && getDigitPos(0) == 0) {
1141 return u
"Least significant digit is zero in long mode";
1143 for (int i
= 0; i
< precision
; i
++) {
1144 if (getDigitPos(i
) >= 10) { return u
"Digit exceeding 10 in long"; }
1145 if (getDigitPos(i
) < 0) { return u
"Digit below 0 in long (?!)"; }
1147 for (int i
= precision
; i
< 16; i
++) {
1148 if (getDigitPos(i
) != 0) { return u
"Nonzero digits outside of range in long"; }
1156 bool DecimalQuantity::operator==(const DecimalQuantity
& other
) const {
1157 // FIXME: Make a faster implementation.
1158 return toString() == other
.toString();
1161 UnicodeString
DecimalQuantity::toString() const {
1162 MaybeStackArray
<char, 30> digits(precision
+ 1);
1163 for (int32_t i
= 0; i
< precision
; i
++) {
1164 digits
[i
] = getDigitPos(precision
- i
- 1) + '0';
1166 digits
[precision
] = 0; // terminate buffer
1171 "<DecimalQuantity %d:%d:%d:%d %s %s%s%s%d>",
1172 (lOptPos
> 999 ? 999 : lOptPos
),
1175 (rOptPos
< -999 ? -999 : rOptPos
),
1176 (usingBytes
? "bytes" : "long"),
1177 (isNegative() ? "-" : ""),
1178 (precision
== 0 ? "0" : digits
.getAlias()),
1181 return UnicodeString(buffer8
, -1, US_INV
);
1184 #endif /* #if !UCONFIG_NO_FORMATTING */