Home | History | Annotate | Download | only in i18n
      1 /*
      2  * Copyright (C) 2015, International Business Machines
      3  * Corporation and others.  All Rights Reserved.
      4  *
      5  * file name: visibledigits.cpp
      6  */
      7 
      8 #include <math.h>
      9 
     10 #include "unicode/utypes.h"
     11 
     12 #if !UCONFIG_NO_FORMATTING
     13 
     14 #include "cstring.h"
     15 #include "decNumber.h"
     16 #include "digitlst.h"
     17 #include "uassert.h"
     18 #include "visibledigits.h"
     19 
     20 static const int32_t kNegative = 1;
     21 static const int32_t kInfinite = 2;
     22 static const int32_t kNaN = 4;
     23 
     24 U_NAMESPACE_BEGIN
     25 
     26 void VisibleDigits::setNegative() {
     27     fFlags |= kNegative;
     28 }
     29 
     30 void VisibleDigits::setNaN() {
     31     fFlags |= kNaN;
     32 }
     33 
     34 void VisibleDigits::setInfinite() {
     35     fFlags |= kInfinite;
     36 }
     37 
     38 void VisibleDigits::clear() {
     39     fInterval.clear();
     40     fDigits.clear();
     41     fExponent = 0;
     42     fFlags = 0;
     43     fAbsIntValue = 0LL;
     44     fAbsIntValueSet = FALSE;
     45     fAbsDoubleValue = 0.0;
     46     fAbsDoubleValueSet = FALSE;
     47 }
     48 
     49 UBool VisibleDigits::isNegative() const {
     50     return (fFlags & kNegative);
     51 }
     52 
     53 UBool VisibleDigits::isNaN() const {
     54     return (fFlags & kNaN);
     55 }
     56 
     57 UBool VisibleDigits::isInfinite() const {
     58     return (fFlags & kInfinite);
     59 }
     60 
     61 int32_t VisibleDigits::getDigitByExponent(int32_t digitPos) const {
     62     if (digitPos < fExponent || digitPos >= fExponent + fDigits.length()) {
     63         return 0;
     64     }
     65     const char *ptr = fDigits.data();
     66     return ptr[digitPos - fExponent];
     67 }
     68 
     69 UBool VisibleDigits::isOverMaxDigits() const {
     70     return (fExponent + fDigits.length() > fInterval.getMostSignificantExclusive());
     71 }
     72 
     73 UBool VisibleDigits::isNaNOrInfinity() const {
     74     return (fFlags & (kInfinite | kNaN)) != 0;
     75 }
     76 
     77 double VisibleDigits::computeAbsDoubleValue() const {
     78     // Take care of NaN and infinity
     79     if (isNaN()) {
     80         return uprv_getNaN();
     81     }
     82     if (isInfinite()) {
     83         return uprv_getInfinity();
     84     }
     85 
     86     // stack allocate a decNumber to hold MAX_DBL_DIGITS+3 significant digits
     87     char rawNumber[sizeof(decNumber) + MAX_DBL_DIGITS+3];
     88     decNumber *numberPtr = (decNumber *) rawNumber;
     89 
     90     int32_t mostSig = fInterval.getMostSignificantExclusive();
     91     int32_t mostSigNonZero = fExponent + fDigits.length();
     92     int32_t end = mostSig > mostSigNonZero ? mostSigNonZero : mostSig;
     93     int32_t leastSig = fInterval.getLeastSignificantInclusive();
     94     int32_t start = leastSig > fExponent ? leastSig : fExponent;
     95     if (end <= start) {
     96         return 0.0;
     97     }
     98     if (start < end - (MAX_DBL_DIGITS+3)) {
     99         start = end - (MAX_DBL_DIGITS+3);
    100     }
    101     uint8_t *pos = numberPtr->lsu;
    102     const char *src = &(fDigits.data()[start - fExponent]);
    103     for (int32_t i = start; i < end; ++i) {
    104         *pos++ = (uint8_t) (*src++);
    105     }
    106     numberPtr->exponent = start;
    107     numberPtr->bits = 0;
    108     numberPtr->digits = end - start;
    109     char str[MAX_DBL_DIGITS+18];
    110     uprv_decNumberToString(numberPtr, str);
    111     U_ASSERT(uprv_strlen(str) < MAX_DBL_DIGITS+18);
    112     char decimalSeparator = DigitList::getStrtodDecimalSeparator();
    113     if (decimalSeparator != '.') {
    114         char *decimalPt = strchr(str, '.');
    115         if (decimalPt != NULL) {
    116             *decimalPt = decimalSeparator;
    117         }
    118     }
    119     char *unused = NULL;
    120     return uprv_strtod(str, &unused);
    121 }
    122 
    123 void VisibleDigits::getFixedDecimal(
    124     double &source, int64_t &intValue, int64_t &f, int64_t &t, int32_t &v, UBool &hasIntValue) const {
    125     source = 0.0;
    126     intValue = 0;
    127     f = 0;
    128     t = 0;
    129     v = 0;
    130     hasIntValue = FALSE;
    131     if (isNaNOrInfinity()) {
    132         return;
    133     }
    134 
    135     // source
    136     if (fAbsDoubleValueSet) {
    137         source = fAbsDoubleValue;
    138     } else {
    139         source = computeAbsDoubleValue();
    140     }
    141 
    142     // visible decimal digits
    143     v = fInterval.getFracDigitCount();
    144 
    145     // intValue
    146 
    147     // If we initialized from an int64 just use that instead of
    148     // calculating
    149     if (fAbsIntValueSet) {
    150         intValue = fAbsIntValue;
    151     } else {
    152         int32_t startPos = fInterval.getMostSignificantExclusive();
    153         if (startPos > 18) {
    154             startPos = 18;
    155         }
    156         // process the integer digits
    157         for (int32_t i = startPos - 1; i >= 0; --i) {
    158             intValue = intValue * 10LL + getDigitByExponent(i);
    159         }
    160         if (intValue == 0LL && startPos > 0) {
    161             intValue = 100000000000000000LL;
    162         }
    163     }
    164 
    165     // f (decimal digits)
    166     // skip over any leading 0's in fraction digits.
    167     int32_t idx = -1;
    168     for (; idx >= -v && getDigitByExponent(idx) == 0; --idx);
    169 
    170     // Only process up to first 18 non zero fraction digits for decimalDigits
    171     // since that is all we can fit into an int64.
    172     for (int32_t i = idx; i >= -v && i > idx - 18; --i) {
    173         f = f * 10LL + getDigitByExponent(i);
    174     }
    175 
    176     // If we have no decimal digits, we don't have an integer value
    177     hasIntValue = (f == 0LL);
    178 
    179     // t (decimal digits without trailing zeros)
    180    t = f;
    181     while (t > 0 && t % 10LL == 0) {
    182         t /= 10;
    183     }
    184 }
    185 
    186 U_NAMESPACE_END
    187 #endif /* #if !UCONFIG_NO_FORMATTING */
    188