• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
setNegative()26 void VisibleDigits::setNegative() {
27     fFlags |= kNegative;
28 }
29 
setNaN()30 void VisibleDigits::setNaN() {
31     fFlags |= kNaN;
32 }
33 
setInfinite()34 void VisibleDigits::setInfinite() {
35     fFlags |= kInfinite;
36 }
37 
clear()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 
isNegative() const49 UBool VisibleDigits::isNegative() const {
50     return (fFlags & kNegative);
51 }
52 
isNaN() const53 UBool VisibleDigits::isNaN() const {
54     return (fFlags & kNaN);
55 }
56 
isInfinite() const57 UBool VisibleDigits::isInfinite() const {
58     return (fFlags & kInfinite);
59 }
60 
getDigitByExponent(int32_t digitPos) const61 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 
isOverMaxDigits() const69 UBool VisibleDigits::isOverMaxDigits() const {
70     return (fExponent + fDigits.length() > fInterval.getMostSignificantExclusive());
71 }
72 
isNaNOrInfinity() const73 UBool VisibleDigits::isNaNOrInfinity() const {
74     return (fFlags & (kInfinite | kNaN)) != 0;
75 }
76 
computeAbsDoubleValue() const77 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 
getFixedDecimal(double & source,int64_t & intValue,int64_t & f,int64_t & t,int32_t & v,UBool & hasIntValue) const123 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