]>
Commit | Line | Data |
---|---|---|
2ca993e8 A |
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 */ |