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