Index: source/i18n/visibledigits.cpp |
diff --git a/source/i18n/visibledigits.cpp b/source/i18n/visibledigits.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a6cbd0fdce276ee73a34bda6fdce5c20c94829d8 |
--- /dev/null |
+++ b/source/i18n/visibledigits.cpp |
@@ -0,0 +1,187 @@ |
+/* |
+ * Copyright (C) 2015, International Business Machines |
+ * Corporation and others. All Rights Reserved. |
+ * |
+ * file name: visibledigits.cpp |
+ */ |
+ |
+#include <math.h> |
+ |
+#include "unicode/utypes.h" |
+ |
+#if !UCONFIG_NO_FORMATTING |
+ |
+#include "cstring.h" |
+#include "decNumber.h" |
+#include "digitlst.h" |
+#include "uassert.h" |
+#include "visibledigits.h" |
+ |
+static const int32_t kNegative = 1; |
+static const int32_t kInfinite = 2; |
+static const int32_t kNaN = 4; |
+ |
+U_NAMESPACE_BEGIN |
+ |
+void VisibleDigits::setNegative() { |
+ fFlags |= kNegative; |
+} |
+ |
+void VisibleDigits::setNaN() { |
+ fFlags |= kNaN; |
+} |
+ |
+void VisibleDigits::setInfinite() { |
+ fFlags |= kInfinite; |
+} |
+ |
+void VisibleDigits::clear() { |
+ fInterval.clear(); |
+ fDigits.clear(); |
+ fExponent = 0; |
+ fFlags = 0; |
+ fAbsIntValue = 0LL; |
+ fAbsIntValueSet = FALSE; |
+ fAbsDoubleValue = 0.0; |
+ fAbsDoubleValueSet = FALSE; |
+} |
+ |
+UBool VisibleDigits::isNegative() const { |
+ return (fFlags & kNegative); |
+} |
+ |
+UBool VisibleDigits::isNaN() const { |
+ return (fFlags & kNaN); |
+} |
+ |
+UBool VisibleDigits::isInfinite() const { |
+ return (fFlags & kInfinite); |
+} |
+ |
+int32_t VisibleDigits::getDigitByExponent(int32_t digitPos) const { |
+ if (digitPos < fExponent || digitPos >= fExponent + fDigits.length()) { |
+ return 0; |
+ } |
+ const char *ptr = fDigits.data(); |
+ return ptr[digitPos - fExponent]; |
+} |
+ |
+UBool VisibleDigits::isOverMaxDigits() const { |
+ return (fExponent + fDigits.length() > fInterval.getMostSignificantExclusive()); |
+} |
+ |
+UBool VisibleDigits::isNaNOrInfinity() const { |
+ return (fFlags & (kInfinite | kNaN)) != 0; |
+} |
+ |
+double VisibleDigits::computeAbsDoubleValue() const { |
+ // Take care of NaN and infinity |
+ if (isNaN()) { |
+ return uprv_getNaN(); |
+ } |
+ if (isInfinite()) { |
+ return uprv_getInfinity(); |
+ } |
+ |
+ // stack allocate a decNumber to hold MAX_DBL_DIGITS+3 significant digits |
+ char rawNumber[sizeof(decNumber) + MAX_DBL_DIGITS+3]; |
+ decNumber *numberPtr = (decNumber *) rawNumber; |
+ |
+ int32_t mostSig = fInterval.getMostSignificantExclusive(); |
+ int32_t mostSigNonZero = fExponent + fDigits.length(); |
+ int32_t end = mostSig > mostSigNonZero ? mostSigNonZero : mostSig; |
+ int32_t leastSig = fInterval.getLeastSignificantInclusive(); |
+ int32_t start = leastSig > fExponent ? leastSig : fExponent; |
+ if (end <= start) { |
+ return 0.0; |
+ } |
+ if (start < end - (MAX_DBL_DIGITS+3)) { |
+ start = end - (MAX_DBL_DIGITS+3); |
+ } |
+ uint8_t *pos = numberPtr->lsu; |
+ const char *src = &(fDigits.data()[start - fExponent]); |
+ for (int32_t i = start; i < end; ++i) { |
+ *pos++ = (uint8_t) (*src++); |
+ } |
+ numberPtr->exponent = start; |
+ numberPtr->bits = 0; |
+ numberPtr->digits = end - start; |
+ char str[MAX_DBL_DIGITS+18]; |
+ uprv_decNumberToString(numberPtr, str); |
+ U_ASSERT(uprv_strlen(str) < MAX_DBL_DIGITS+18); |
+ char decimalSeparator = DigitList::getStrtodDecimalSeparator(); |
+ if (decimalSeparator != '.') { |
+ char *decimalPt = strchr(str, '.'); |
+ if (decimalPt != NULL) { |
+ *decimalPt = decimalSeparator; |
+ } |
+ } |
+ char *unused = NULL; |
+ return uprv_strtod(str, &unused); |
+} |
+ |
+void VisibleDigits::getFixedDecimal( |
+ double &source, int64_t &intValue, int64_t &f, int64_t &t, int32_t &v, UBool &hasIntValue) const { |
+ source = 0.0; |
+ intValue = 0; |
+ f = 0; |
+ t = 0; |
+ v = 0; |
+ hasIntValue = FALSE; |
+ if (isNaNOrInfinity()) { |
+ return; |
+ } |
+ |
+ // source |
+ if (fAbsDoubleValueSet) { |
+ source = fAbsDoubleValue; |
+ } else { |
+ source = computeAbsDoubleValue(); |
+ } |
+ |
+ // visible decimal digits |
+ v = fInterval.getFracDigitCount(); |
+ |
+ // intValue |
+ |
+ // If we initialized from an int64 just use that instead of |
+ // calculating |
+ if (fAbsIntValueSet) { |
+ intValue = fAbsIntValue; |
+ } else { |
+ int32_t startPos = fInterval.getMostSignificantExclusive(); |
+ if (startPos > 18) { |
+ startPos = 18; |
+ } |
+ // process the integer digits |
+ for (int32_t i = startPos - 1; i >= 0; --i) { |
+ intValue = intValue * 10LL + getDigitByExponent(i); |
+ } |
+ if (intValue == 0LL && startPos > 0) { |
+ intValue = 100000000000000000LL; |
+ } |
+ } |
+ |
+ // f (decimal digits) |
+ // skip over any leading 0's in fraction digits. |
+ int32_t idx = -1; |
+ for (; idx >= -v && getDigitByExponent(idx) == 0; --idx); |
+ |
+ // Only process up to first 18 non zero fraction digits for decimalDigits |
+ // since that is all we can fit into an int64. |
+ for (int32_t i = idx; i >= -v && i > idx - 18; --i) { |
+ f = f * 10LL + getDigitByExponent(i); |
+ } |
+ |
+ // If we have no decimal digits, we don't have an integer value |
+ hasIntValue = (f == 0LL); |
+ |
+ // t (decimal digits without trailing zeros) |
+ t = f; |
+ while (t > 0 && t % 10LL == 0) { |
+ t /= 10; |
+ } |
+} |
+ |
+U_NAMESPACE_END |
+#endif /* #if !UCONFIG_NO_FORMATTING */ |