// Copyright (C) 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html /* * Copyright (C) 2016, 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 struct { decNumber decNum; char digits[MAX_DBL_DIGITS+3]; } decNumberWithStorage; decNumber *numberPtr = &decNumberWithStorage.decNum; 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 *unused = NULL; return DigitList::decimalStrToDouble(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 */