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