| /* |
| * Copyright (C) 2015, International Business Machines |
| * Corporation and others. All Rights Reserved. |
| * |
| * file name: visibledigits.cpp |
| */ |
| |
| #if !defined(STARBOARD) |
| #include <math.h> |
| #endif |
| |
| #include "unicode/utypes.h" |
| |
| #if !UCONFIG_NO_FORMATTING |
| |
| #if defined(STARBOARD) |
| #include "starboard/client_porting/poem/assert_poem.h" |
| #include "starboard/client_porting/poem/string_poem.h" |
| #endif // defined(STARBOARD) |
| #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 */ |