summaryrefslogtreecommitdiff
path: root/deps/icu-small/source/i18n/number_decimalquantity.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'deps/icu-small/source/i18n/number_decimalquantity.cpp')
-rw-r--r--deps/icu-small/source/i18n/number_decimalquantity.cpp414
1 files changed, 282 insertions, 132 deletions
diff --git a/deps/icu-small/source/i18n/number_decimalquantity.cpp b/deps/icu-small/source/i18n/number_decimalquantity.cpp
index b68df26ba2..9d80e3349c 100644
--- a/deps/icu-small/source/i18n/number_decimalquantity.cpp
+++ b/deps/icu-small/source/i18n/number_decimalquantity.cpp
@@ -3,25 +3,30 @@
#include "unicode/utypes.h"
-#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
+#if !UCONFIG_NO_FORMATTING
-#include "uassert.h"
+#include <cstdlib>
#include <cmath>
-#include "cmemory.h"
-#include "decNumber.h"
#include <limits>
+#include <stdlib.h>
+
+#include "unicode/plurrule.h"
+#include "cmemory.h"
+#include "number_decnum.h"
+#include "putilimp.h"
#include "number_decimalquantity.h"
-#include "decContext.h"
-#include "decNumber.h"
#include "number_roundingutils.h"
#include "double-conversion.h"
-#include "unicode/plurrule.h"
+#include "charstr.h"
+#include "number_utils.h"
+#include "uassert.h"
using namespace icu;
using namespace icu::number;
using namespace icu::number::impl;
using icu::double_conversion::DoubleToStringConverter;
+using icu::double_conversion::StringToDoubleConverter;
namespace {
@@ -29,25 +34,6 @@ int8_t NEGATIVE_FLAG = 1;
int8_t INFINITY_FLAG = 2;
int8_t NAN_FLAG = 4;
-static constexpr int32_t DEFAULT_DIGITS = 34;
-typedef MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS> DecNumberWithStorage;
-
-/** Helper function to convert a decNumber-compatible string into a decNumber. */
-void stringToDecNumber(StringPiece n, DecNumberWithStorage &dn) {
- decContext set;
- uprv_decContextDefault(&set, DEC_INIT_BASE);
- uprv_decContextSetRounding(&set, DEC_ROUND_HALF_EVEN);
- set.traps = 0; // no traps, thank you
- if (n.length() > DEFAULT_DIGITS) {
- dn.resize(n.length(), 0);
- set.digits = n.length();
- } else {
- set.digits = DEFAULT_DIGITS;
- }
- uprv_decNumberFromString(dn.getAlias(), n.data(), &set);
- U_ASSERT(DECDPUN == 1);
-}
-
/** Helper function for safe subtraction (no overflow). */
inline int32_t safeSubtract(int32_t a, int32_t b) {
// Note: In C++, signed integer subtraction is undefined behavior.
@@ -83,6 +69,7 @@ static double DOUBLE_MULTIPLIERS[] = {
} // namespace
+icu::IFixedDecimal::~IFixedDecimal() = default;
DecimalQuantity::DecimalQuantity() {
setBcdToZero();
@@ -101,11 +88,30 @@ DecimalQuantity::DecimalQuantity(const DecimalQuantity &other) {
*this = other;
}
+DecimalQuantity::DecimalQuantity(DecimalQuantity&& src) U_NOEXCEPT {
+ *this = std::move(src);
+}
+
DecimalQuantity &DecimalQuantity::operator=(const DecimalQuantity &other) {
if (this == &other) {
return *this;
}
copyBcdFrom(other);
+ copyFieldsFrom(other);
+ return *this;
+}
+
+DecimalQuantity& DecimalQuantity::operator=(DecimalQuantity&& src) U_NOEXCEPT {
+ if (this == &src) {
+ return *this;
+ }
+ moveBcdFrom(src);
+ copyFieldsFrom(src);
+ return *this;
+}
+
+void DecimalQuantity::copyFieldsFrom(const DecimalQuantity& other) {
+ bogus = other.bogus;
lOptPos = other.lOptPos;
lReqPos = other.lReqPos;
rReqPos = other.rReqPos;
@@ -116,7 +122,6 @@ DecimalQuantity &DecimalQuantity::operator=(const DecimalQuantity &other) {
origDouble = other.origDouble;
origDelta = other.origDelta;
isApproximate = other.isApproximate;
- return *this;
}
void DecimalQuantity::clear() {
@@ -129,10 +134,16 @@ void DecimalQuantity::clear() {
}
void DecimalQuantity::setIntegerLength(int32_t minInt, int32_t maxInt) {
- // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
+ // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
U_ASSERT(minInt >= 0);
U_ASSERT(maxInt >= minInt);
+ // Special behavior: do not set minInt to be less than what is already set.
+ // This is so significant digits rounding can set the integer length.
+ if (minInt < lReqPos) {
+ minInt = lReqPos;
+ }
+
// Save values into internal state
// Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
lOptPos = maxInt;
@@ -140,7 +151,7 @@ void DecimalQuantity::setIntegerLength(int32_t minInt, int32_t maxInt) {
}
void DecimalQuantity::setFractionLength(int32_t minFrac, int32_t maxFrac) {
- // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
+ // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
U_ASSERT(minFrac >= 0);
U_ASSERT(maxFrac >= minFrac);
@@ -160,29 +171,53 @@ uint64_t DecimalQuantity::getPositionFingerprint() const {
}
void DecimalQuantity::roundToIncrement(double roundingIncrement, RoundingMode roundingMode,
- int32_t minMaxFrac, UErrorCode& status) {
- // TODO: This is innefficient. Improve?
- // TODO: Should we convert to decNumber instead?
+ int32_t maxFrac, UErrorCode& status) {
+ // TODO(13701): This is innefficient. Improve?
+ // TODO(13701): Should we convert to decNumber instead?
+ roundToInfinity();
double temp = toDouble();
temp /= roundingIncrement;
- setToDouble(temp);
- roundToMagnitude(0, roundingMode, status);
- temp = toDouble();
+ // Use another DecimalQuantity to perform the actual rounding...
+ DecimalQuantity dq;
+ dq.setToDouble(temp);
+ dq.roundToMagnitude(0, roundingMode, status);
+ temp = dq.toDouble();
temp *= roundingIncrement;
setToDouble(temp);
// Since we reset the value to a double, we need to specify the rounding boundary
// in order to get the DecimalQuantity out of approximation mode.
- roundToMagnitude(-minMaxFrac, roundingMode, status);
+ // NOTE: In Java, we have minMaxFrac, but in C++, the two are differentiated.
+ roundToMagnitude(-maxFrac, roundingMode, status);
}
-void DecimalQuantity::multiplyBy(int32_t multiplicand) {
+void DecimalQuantity::multiplyBy(const DecNum& multiplicand, UErrorCode& status) {
if (isInfinite() || isZero() || isNaN()) {
return;
}
- // TODO: Should we convert to decNumber instead?
- double temp = toDouble();
- temp *= multiplicand;
- setToDouble(temp);
+ // Convert to DecNum, multiply, and convert back.
+ DecNum decnum;
+ toDecNum(decnum, status);
+ if (U_FAILURE(status)) { return; }
+ decnum.multiplyBy(multiplicand, status);
+ if (U_FAILURE(status)) { return; }
+ setToDecNum(decnum, status);
+}
+
+void DecimalQuantity::divideBy(const DecNum& divisor, UErrorCode& status) {
+ if (isInfinite() || isZero() || isNaN()) {
+ return;
+ }
+ // Convert to DecNum, multiply, and convert back.
+ DecNum decnum;
+ toDecNum(decnum, status);
+ if (U_FAILURE(status)) { return; }
+ decnum.divideBy(divisor, status);
+ if (U_FAILURE(status)) { return; }
+ setToDecNum(decnum, status);
+}
+
+void DecimalQuantity::negate() {
+ flags ^= NEGATIVE_FLAG;
}
int32_t DecimalQuantity::getMagnitude() const {
@@ -190,21 +225,17 @@ int32_t DecimalQuantity::getMagnitude() const {
return scale + precision - 1;
}
-void DecimalQuantity::adjustMagnitude(int32_t delta) {
+bool DecimalQuantity::adjustMagnitude(int32_t delta) {
if (precision != 0) {
- scale += delta;
- origDelta += delta;
- }
-}
-
-StandardPlural::Form DecimalQuantity::getStandardPlural(const PluralRules *rules) const {
- if (rules == nullptr) {
- // Fail gracefully if the user didn't provide a PluralRules
- return StandardPlural::Form::OTHER;
- } else {
- UnicodeString ruleString = rules->select(*this);
- return StandardPlural::orOtherFromString(ruleString);
+ // i.e., scale += delta; origDelta += delta
+ bool overflow = uprv_add32_overflow(scale, delta, &scale);
+ overflow = uprv_add32_overflow(origDelta, delta, &origDelta) || overflow;
+ // Make sure that precision + scale won't overflow, either
+ int32_t dummy;
+ overflow = overflow || uprv_add32_overflow(scale, precision, &dummy);
+ return overflow;
}
+ return false;
}
double DecimalQuantity::getPluralOperand(PluralOperand operand) const {
@@ -214,7 +245,8 @@ double DecimalQuantity::getPluralOperand(PluralOperand operand) const {
switch (operand) {
case PLURAL_OPERAND_I:
- return static_cast<double>(toLong());
+ // Invert the negative sign if necessary
+ return static_cast<double>(isNegative() ? -toLong(true) : toLong(true));
case PLURAL_OPERAND_F:
return static_cast<double>(toFractionLong(true));
case PLURAL_OPERAND_T:
@@ -228,6 +260,10 @@ double DecimalQuantity::getPluralOperand(PluralOperand operand) const {
}
}
+bool DecimalQuantity::hasIntegerValue() const {
+ return scale >= 0;
+}
+
int32_t DecimalQuantity::getUpperDisplayMagnitude() const {
// If this assertion fails, you need to call roundToInfinity() or some other rounding method.
// See the comment in the header file explaining the "isApproximate" field.
@@ -287,7 +323,10 @@ bool DecimalQuantity::isZero() const {
DecimalQuantity &DecimalQuantity::setToInt(int32_t n) {
setBcdToZero();
flags = 0;
- if (n < 0) {
+ if (n == INT32_MIN) {
+ flags |= NEGATIVE_FLAG;
+ // leave as INT32_MIN; handled below in _setToInt()
+ } else if (n < 0) {
flags |= NEGATIVE_FLAG;
n = -n;
}
@@ -309,7 +348,7 @@ void DecimalQuantity::_setToInt(int32_t n) {
DecimalQuantity &DecimalQuantity::setToLong(int64_t n) {
setBcdToZero();
flags = 0;
- if (n < 0) {
+ if (n < 0 && n > INT64_MIN) {
flags |= NEGATIVE_FLAG;
n = -n;
}
@@ -322,10 +361,12 @@ DecimalQuantity &DecimalQuantity::setToLong(int64_t n) {
void DecimalQuantity::_setToLong(int64_t n) {
if (n == INT64_MIN) {
- static const char *int64minStr = "9.223372036854775808E+18";
- DecNumberWithStorage dn;
- stringToDecNumber(int64minStr, dn);
- readDecNumberToBcd(dn.getAlias());
+ DecNum decnum;
+ UErrorCode localStatus = U_ZERO_ERROR;
+ decnum.setTo("9.223372036854775808E+18", localStatus);
+ if (U_FAILURE(localStatus)) { return; } // unexpected
+ flags |= NEGATIVE_FLAG;
+ readDecNumberToBcd(decnum);
} else if (n <= INT32_MAX) {
readIntToBcd(static_cast<int32_t>(n));
} else {
@@ -337,7 +378,7 @@ DecimalQuantity &DecimalQuantity::setToDouble(double n) {
setBcdToZero();
flags = 0;
// signbit() from <math.h> handles +0.0 vs -0.0
- if (std::signbit(n) != 0) {
+ if (std::signbit(n)) {
flags |= NEGATIVE_FLAG;
n = -n;
}
@@ -424,51 +465,107 @@ void DecimalQuantity::convertToAccurateDouble() {
explicitExactDouble = true;
}
-DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n) {
+DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n, UErrorCode& status) {
setBcdToZero();
flags = 0;
- DecNumberWithStorage dn;
- stringToDecNumber(n, dn);
+ // Compute the decNumber representation
+ DecNum decnum;
+ decnum.setTo(n, status);
- // The code path for decNumber is modeled after BigDecimal in Java.
- if (decNumberIsNegative(dn.getAlias())) {
- flags |= NEGATIVE_FLAG;
- }
- if (!decNumberIsZero(dn.getAlias())) {
- _setToDecNumber(dn.getAlias());
- }
+ _setToDecNum(decnum, status);
return *this;
}
-void DecimalQuantity::_setToDecNumber(decNumber *n) {
- // Java fastpaths for ints here. In C++, just always read directly from the decNumber.
- readDecNumberToBcd(n);
- compact();
+DecimalQuantity& DecimalQuantity::setToDecNum(const DecNum& decnum, UErrorCode& status) {
+ setBcdToZero();
+ flags = 0;
+
+ _setToDecNum(decnum, status);
+ return *this;
}
-int64_t DecimalQuantity::toLong() const {
- int64_t result = 0L;
- for (int32_t magnitude = scale + precision - 1; magnitude >= 0; magnitude--) {
+void DecimalQuantity::_setToDecNum(const DecNum& decnum, UErrorCode& status) {
+ if (U_FAILURE(status)) { return; }
+ if (decnum.isNegative()) {
+ flags |= NEGATIVE_FLAG;
+ }
+ if (!decnum.isZero()) {
+ readDecNumberToBcd(decnum);
+ compact();
+ }
+}
+
+int64_t DecimalQuantity::toLong(bool truncateIfOverflow) const {
+ // NOTE: Call sites should be guarded by fitsInLong(), like this:
+ // if (dq.fitsInLong()) { /* use dq.toLong() */ } else { /* use some fallback */ }
+ // Fallback behavior upon truncateIfOverflow is to truncate at 17 digits.
+ uint64_t result = 0L;
+ int32_t upperMagnitude = std::min(scale + precision, lOptPos) - 1;
+ if (truncateIfOverflow) {
+ upperMagnitude = std::min(upperMagnitude, 17);
+ }
+ for (int32_t magnitude = upperMagnitude; magnitude >= 0; magnitude--) {
result = result * 10 + getDigitPos(magnitude - scale);
}
- return result;
+ if (isNegative()) {
+ return static_cast<int64_t>(0LL - result); // i.e., -result
+ }
+ return static_cast<int64_t>(result);
}
-int64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const {
- int64_t result = 0L;
+uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const {
+ uint64_t result = 0L;
int32_t magnitude = -1;
- for (; (magnitude >= scale || (includeTrailingZeros && magnitude >= rReqPos)) &&
- magnitude >= rOptPos; magnitude--) {
+ int32_t lowerMagnitude = std::max(scale, rOptPos);
+ if (includeTrailingZeros) {
+ lowerMagnitude = std::min(lowerMagnitude, rReqPos);
+ }
+ for (; magnitude >= lowerMagnitude && result <= 1e18L; magnitude--) {
result = result * 10 + getDigitPos(magnitude - scale);
}
+ // Remove trailing zeros; this can happen during integer overflow cases.
+ if (!includeTrailingZeros) {
+ while (result > 0 && (result % 10) == 0) {
+ result /= 10;
+ }
+ }
return result;
}
-double DecimalQuantity::toDouble() const {
- if (isApproximate) {
- return toDoubleFromOriginal();
+bool DecimalQuantity::fitsInLong(bool ignoreFraction) const {
+ if (isZero()) {
+ return true;
+ }
+ if (scale < 0 && !ignoreFraction) {
+ return false;
}
+ int magnitude = getMagnitude();
+ if (magnitude < 18) {
+ return true;
+ }
+ if (magnitude > 18) {
+ return false;
+ }
+ // Hard case: the magnitude is 10^18.
+ // The largest int64 is: 9,223,372,036,854,775,807
+ for (int p = 0; p < precision; p++) {
+ int8_t digit = getDigit(18 - p);
+ static int8_t INT64_BCD[] = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 };
+ if (digit < INT64_BCD[p]) {
+ return true;
+ } else if (digit > INT64_BCD[p]) {
+ return false;
+ }
+ }
+ // Exactly equal to max long plus one.
+ return isNegative();
+}
+
+double DecimalQuantity::toDouble() const {
+ // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
+ // See the comment in the header file explaining the "isApproximate" field.
+ U_ASSERT(!isApproximate);
if (isNaN()) {
return NAN;
@@ -476,42 +573,37 @@ double DecimalQuantity::toDouble() const {
return isNegative() ? -INFINITY : INFINITY;
}
- int64_t tempLong = 0L;
- int32_t lostDigits = precision - (precision < 17 ? precision : 17);
- for (int shift = precision - 1; shift >= lostDigits; shift--) {
- tempLong = tempLong * 10 + getDigitPos(shift);
+ // We are processing well-formed input, so we don't need any special options to StringToDoubleConverter.
+ StringToDoubleConverter converter(0, 0, 0, "", "");
+ UnicodeString numberString = this->toScientificString();
+ int32_t count;
+ return converter.StringToDouble(
+ reinterpret_cast<const uint16_t*>(numberString.getBuffer()),
+ numberString.length(),
+ &count);
+}
+
+void DecimalQuantity::toDecNum(DecNum& output, UErrorCode& status) const {
+ // Special handling for zero
+ if (precision == 0) {
+ output.setTo("0", status);
}
- double result = static_cast<double>(tempLong);
- int32_t _scale = scale + lostDigits;
- if (_scale >= 0) {
- // 1e22 is the largest exact double.
- int32_t i = _scale;
- for (; i >= 22; i -= 22) result *= 1e22;
- result *= DOUBLE_MULTIPLIERS[i];
- } else {
- // 1e22 is the largest exact double.
- int32_t i = _scale;
- for (; i <= -22; i += 22) result /= 1e22;
- result /= DOUBLE_MULTIPLIERS[-i];
+
+ // Use the BCD constructor. We need to do a little bit of work to convert, though.
+ // The decNumber constructor expects most-significant first, but we store least-significant first.
+ MaybeStackArray<uint8_t, 20> ubcd(precision);
+ for (int32_t m = 0; m < precision; m++) {
+ ubcd[precision - m - 1] = static_cast<uint8_t>(getDigitPos(m));
}
- if (isNegative()) { result = -result; }
- return result;
+ output.setTo(ubcd.getAlias(), precision, scale, isNegative(), status);
}
-double DecimalQuantity::toDoubleFromOriginal() const {
- double result = origDouble;
- int32_t delta = origDelta;
- if (delta >= 0) {
- // 1e22 is the largest exact double.
- for (; delta >= 22; delta -= 22) result *= 1e22;
- result *= DOUBLE_MULTIPLIERS[delta];
- } else {
- // 1e22 is the largest exact double.
- for (; delta <= -22; delta += 22) result /= 1e22;
- result /= DOUBLE_MULTIPLIERS[-delta];
+void DecimalQuantity::truncate() {
+ if (scale < 0) {
+ shiftRight(-scale);
+ scale = 0;
+ compact();
}
- if (isNegative()) { result *= -1; }
- return result;
}
void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) {
@@ -689,17 +781,63 @@ void DecimalQuantity::appendDigit(int8_t value, int32_t leadingZeros, bool appen
}
UnicodeString DecimalQuantity::toPlainString() const {
+ U_ASSERT(!isApproximate);
UnicodeString sb;
if (isNegative()) {
sb.append(u'-');
}
+ if (precision == 0 || getMagnitude() < 0) {
+ sb.append(u'0');
+ }
for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
+ if (m == -1) { sb.append(u'.'); }
sb.append(getDigit(m) + u'0');
- if (m == 0) { sb.append(u'.'); }
}
return sb;
}
+UnicodeString DecimalQuantity::toScientificString() const {
+ U_ASSERT(!isApproximate);
+ UnicodeString result;
+ if (isNegative()) {
+ result.append(u'-');
+ }
+ if (precision == 0) {
+ result.append(u"0E+0", -1);
+ return result;
+ }
+ // NOTE: It is not safe to add to lOptPos (aka maxInt) or subtract from
+ // rOptPos (aka -maxFrac) due to overflow.
+ int32_t upperPos = std::min(precision + scale, lOptPos) - scale - 1;
+ int32_t lowerPos = std::max(scale, rOptPos) - scale;
+ int32_t p = upperPos;
+ result.append(u'0' + getDigitPos(p));
+ if ((--p) >= lowerPos) {
+ result.append(u'.');
+ for (; p >= lowerPos; p--) {
+ result.append(u'0' + getDigitPos(p));
+ }
+ }
+ result.append(u'E');
+ int32_t _scale = upperPos + scale;
+ if (_scale < 0) {
+ _scale *= -1;
+ result.append(u'-');
+ } else {
+ result.append(u'+');
+ }
+ if (_scale == 0) {
+ result.append(u'0');
+ }
+ int32_t insertIndex = result.length();
+ while (_scale > 0) {
+ std::div_t res = std::div(_scale, 10);
+ result.insert(insertIndex, u'0' + res.rem);
+ _scale = res.quot;
+ }
+ return result;
+}
+
////////////////////////////////////////////////////
/// End of DecimalQuantity_AbstractBCD.java ///
/// Start of DecimalQuantity_DualStorageBCD.java ///
@@ -707,7 +845,7 @@ UnicodeString DecimalQuantity::toPlainString() const {
int8_t DecimalQuantity::getDigitPos(int32_t position) const {
if (usingBytes) {
- if (position < 0 || position > precision) { return 0; }
+ if (position < 0 || position >= precision) { return 0; }
return fBCD.bcdBytes.ptr[position];
} else {
if (position < 0 || position >= 16) { return 0; }
@@ -819,7 +957,8 @@ void DecimalQuantity::readLongToBcd(int64_t n) {
}
}
-void DecimalQuantity::readDecNumberToBcd(decNumber *dn) {
+void DecimalQuantity::readDecNumberToBcd(const DecNum& decnum) {
+ const decNumber* dn = decnum.getRawDecNumber();
if (dn->digits > 16) {
ensureCapacity(dn->digits);
for (int32_t i = 0; i < dn->digits; i++) {
@@ -919,7 +1058,7 @@ void DecimalQuantity::ensureCapacity(int32_t capacity) {
auto bcd1 = static_cast<int8_t*>(uprv_malloc(capacity * 2 * sizeof(int8_t)));
uprv_memcpy(bcd1, fBCD.bcdBytes.ptr, oldCapacity * sizeof(int8_t));
// Initialize the rest of the byte array to zeros (this is done automatically in Java)
- uprv_memset(fBCD.bcdBytes.ptr + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t));
+ uprv_memset(bcd1 + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t));
uprv_free(fBCD.bcdBytes.ptr);
fBCD.bcdBytes.ptr = bcd1;
fBCD.bcdBytes.len = capacity * 2;
@@ -962,6 +1101,20 @@ void DecimalQuantity::copyBcdFrom(const DecimalQuantity &other) {
}
}
+void DecimalQuantity::moveBcdFrom(DecimalQuantity &other) {
+ setBcdToZero();
+ if (other.usingBytes) {
+ usingBytes = true;
+ fBCD.bcdBytes.ptr = other.fBCD.bcdBytes.ptr;
+ fBCD.bcdBytes.len = other.fBCD.bcdBytes.len;
+ // Take ownership away from the old instance:
+ other.fBCD.bcdBytes.ptr = nullptr;
+ other.usingBytes = false;
+ } else {
+ fBCD.bcdLong = other.fBCD.bcdLong;
+ }
+}
+
const char16_t* DecimalQuantity::checkHealth() const {
if (usingBytes) {
if (precision == 0) { return u"Zero precision but we are in byte mode"; }
@@ -1000,6 +1153,11 @@ const char16_t* DecimalQuantity::checkHealth() const {
return nullptr;
}
+bool DecimalQuantity::operator==(const DecimalQuantity& other) const {
+ // FIXME: Make a faster implementation.
+ return toString() == other.toString();
+}
+
UnicodeString DecimalQuantity::toString() const {
MaybeStackArray<char, 30> digits(precision + 1);
for (int32_t i = 0; i < precision; i++) {
@@ -1010,25 +1168,17 @@ UnicodeString DecimalQuantity::toString() const {
snprintf(
buffer8,
sizeof(buffer8),
- "<DecimalQuantity %d:%d:%d:%d %s %s%s%d>",
+ "<DecimalQuantity %d:%d:%d:%d %s %s%s%s%d>",
(lOptPos > 999 ? 999 : lOptPos),
lReqPos,
rReqPos,
(rOptPos < -999 ? -999 : rOptPos),
(usingBytes ? "bytes" : "long"),
+ (isNegative() ? "-" : ""),
(precision == 0 ? "0" : digits.getAlias()),
"E",
scale);
return UnicodeString(buffer8, -1, US_INV);
}
-UnicodeString DecimalQuantity::toNumberString() const {
- MaybeStackArray<char, 30> digits(precision + 11);
- for (int32_t i = 0; i < precision; i++) {
- digits[i] = getDigitPos(precision - i - 1) + '0';
- }
- snprintf(digits.getAlias() + precision, 11, "E%d", scale);
- return UnicodeString(digits.getAlias(), -1, US_INV);
-}
-
#endif /* #if !UCONFIG_NO_FORMATTING */