text: // © 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 */
  