Index: source/i18n/digitlst.cpp |
diff --git a/source/i18n/digitlst.cpp b/source/i18n/digitlst.cpp |
index 8de732487e8bea4e409b9a134575c0856a99a1b2..bdd3c92bace6a5249a9a8b40b7d8c92c71d0a11d 100644 |
--- a/source/i18n/digitlst.cpp |
+++ b/source/i18n/digitlst.cpp |
@@ -1,6 +1,6 @@ |
/* |
********************************************************************** |
-* Copyright (C) 1997-2014, International Business Machines |
+* Copyright (C) 1997-2015, International Business Machines |
* Corporation and others. All Rights Reserved. |
********************************************************************** |
* |
@@ -34,6 +34,7 @@ |
#include "mutex.h" |
#include "putilimp.h" |
#include "uassert.h" |
+#include "digitinterval.h" |
#include <stdlib.h> |
#include <limits.h> |
#include <string.h> |
@@ -396,6 +397,27 @@ DigitList::append(char digit) |
internalClear(); |
} |
+char DigitList::getStrtodDecimalSeparator() { |
+ // TODO: maybe use andy's pthread once. |
+ static char gDecimal = 0; |
+ char result; |
+ { |
+ Mutex mutex; |
+ result = gDecimal;; |
+ if (result == 0) { |
+ // We need to know the decimal separator character that will be used with strtod(). |
+ // Depends on the C runtime global locale. |
+ // Most commonly is '.' |
+ // TODO: caching could fail if the global locale is changed on the fly. |
+ char rep[MAX_DIGITS]; |
+ sprintf(rep, "%+1.1f", 1.0); |
+ result = rep[2]; |
+ gDecimal = result;; |
+ } |
+ } |
+ return result; |
+} |
+ |
// ------------------------------------- |
/** |
@@ -492,7 +514,7 @@ DigitList::getDouble() const |
int32_t DigitList::getLong() /*const*/ |
{ |
int32_t result = 0; |
- if (fDecNumber->digits + fDecNumber->exponent > 10) { |
+ if (getUpperExponent() > 10) { |
// Overflow, absolute value too big. |
return result; |
} |
@@ -522,7 +544,7 @@ int64_t DigitList::getInt64() /*const*/ { |
// Return 0 if out of range. |
// Range of in64_t is -9223372036854775808 to 9223372036854775807 (19 digits) |
// |
- if (fDecNumber->digits + fDecNumber->exponent > 19) { |
+ if (getUpperExponent() > 19) { |
// Overflow, absolute value too big. |
return 0; |
} |
@@ -536,7 +558,7 @@ int64_t DigitList::getInt64() /*const*/ { |
// TODO: It would be faster to store a table of powers of ten to multiply by |
// instead of looping over zero digits, multiplying each time. |
- int32_t numIntDigits = fDecNumber->digits + fDecNumber->exponent; |
+ int32_t numIntDigits = getUpperExponent(); |
uint64_t value = 0; |
for (int32_t i = 0; i < numIntDigits; i++) { |
// Loop is iterating over digits starting with the most significant. |
@@ -611,7 +633,7 @@ DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/ |
// Negative Zero, not ingored. Cannot represent as a long. |
return FALSE; |
} |
- if (fDecNumber->digits + fDecNumber->exponent < 10) { |
+ if (getUpperExponent() < 10) { |
// The number is 9 or fewer digits. |
// The max and min int32 are 10 digts, so this number fits. |
// This is the common case. |
@@ -658,7 +680,7 @@ DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/ |
// Negative Zero, not ingored. Cannot represent as a long. |
return FALSE; |
} |
- if (fDecNumber->digits + fDecNumber->exponent < 19) { |
+ if (getUpperExponent() < 19) { |
// The number is 18 or fewer digits. |
// The max and min int64 are 19 digts, so this number fits. |
// This is the common case. |
@@ -832,6 +854,9 @@ DigitList::set(double source) |
*/ |
void |
DigitList::mult(const DigitList &other, UErrorCode &status) { |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
fContext.status = 0; |
int32_t requiredDigits = this->digits() + other.digits(); |
if (requiredDigits > fContext.digits) { |
@@ -902,18 +927,23 @@ DigitList::ensureCapacity(int32_t requestedCapacity, UErrorCode &status) { |
void |
DigitList::round(int32_t maximumDigits) |
{ |
+ reduce(); |
+ if (maximumDigits >= fDecNumber->digits) { |
+ return; |
+ } |
int32_t savedDigits = fContext.digits; |
fContext.digits = maximumDigits; |
uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext); |
fContext.digits = savedDigits; |
uprv_decNumberTrim(fDecNumber); |
+ reduce(); |
internalClear(); |
} |
void |
DigitList::roundFixedPoint(int32_t maximumFractionDigits) { |
- trim(); // Remove trailing zeros. |
+ reduce(); // Remove trailing zeros. |
if (fDecNumber->exponent >= -maximumFractionDigits) { |
return; |
} |
@@ -923,7 +953,7 @@ DigitList::roundFixedPoint(int32_t maximumFractionDigits) { |
scale.lsu[0] = 1; |
uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext); |
- trim(); |
+ reduce(); |
internalClear(); |
} |
@@ -942,6 +972,98 @@ DigitList::isZero() const |
return decNumberIsZero(fDecNumber); |
} |
+// ------------------------------------- |
+int32_t |
+DigitList::getUpperExponent() const { |
+ return fDecNumber->digits + fDecNumber->exponent; |
+} |
+ |
+DigitInterval & |
+DigitList::getSmallestInterval(DigitInterval &result) const { |
+ result.setLeastSignificantInclusive(fDecNumber->exponent); |
+ result.setMostSignificantExclusive(getUpperExponent()); |
+ return result; |
+} |
+ |
+uint8_t |
+DigitList::getDigitByExponent(int32_t exponent) const { |
+ int32_t idx = exponent - fDecNumber->exponent; |
+ if (idx < 0 || idx >= fDecNumber->digits) { |
+ return 0; |
+ } |
+ return fDecNumber->lsu[idx]; |
+} |
+ |
+void |
+DigitList::appendDigitsTo(CharString &str, UErrorCode &status) const { |
+ str.append((const char *) fDecNumber->lsu, fDecNumber->digits, status); |
+} |
+ |
+void |
+DigitList::roundAtExponent(int32_t exponent, int32_t maxSigDigits) { |
+ reduce(); |
+ if (maxSigDigits < fDecNumber->digits) { |
+ int32_t minExponent = getUpperExponent() - maxSigDigits; |
+ if (exponent < minExponent) { |
+ exponent = minExponent; |
+ } |
+ } |
+ if (exponent <= fDecNumber->exponent) { |
+ return; |
+ } |
+ int32_t digits = getUpperExponent() - exponent; |
+ if (digits > 0) { |
+ round(digits); |
+ } else { |
+ roundFixedPoint(-exponent); |
+ } |
+} |
+ |
+void |
+DigitList::quantize(const DigitList &quantity, UErrorCode &status) { |
+ if (U_FAILURE(status)) { |
+ return; |
+ } |
+ div(quantity, status); |
+ roundAtExponent(0); |
+ mult(quantity, status); |
+ reduce(); |
+} |
+ |
+int32_t |
+DigitList::getScientificExponent( |
+ int32_t minIntDigitCount, int32_t exponentMultiplier) const { |
+ // The exponent for zero is always zero. |
+ if (isZero()) { |
+ return 0; |
+ } |
+ int32_t intDigitCount = getUpperExponent(); |
+ int32_t exponent; |
+ if (intDigitCount >= minIntDigitCount) { |
+ int32_t maxAdjustment = intDigitCount - minIntDigitCount; |
+ exponent = (maxAdjustment / exponentMultiplier) * exponentMultiplier; |
+ } else { |
+ int32_t minAdjustment = minIntDigitCount - intDigitCount; |
+ exponent = ((minAdjustment + exponentMultiplier - 1) / exponentMultiplier) * -exponentMultiplier; |
+ } |
+ return exponent; |
+} |
+ |
+int32_t |
+DigitList::toScientific( |
+ int32_t minIntDigitCount, int32_t exponentMultiplier) { |
+ int32_t exponent = getScientificExponent( |
+ minIntDigitCount, exponentMultiplier); |
+ shiftDecimalRight(-exponent); |
+ return exponent; |
+} |
+ |
+void |
+DigitList::shiftDecimalRight(int32_t n) { |
+ fDecNumber->exponent += n; |
+ internalClear(); |
+} |
+ |
U_NAMESPACE_END |
#endif // #if !UCONFIG_NO_FORMATTING |