Line data Source code
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 0 : void VisibleDigits::setNegative() {
29 0 : fFlags |= kNegative;
30 0 : }
31 :
32 0 : void VisibleDigits::setNaN() {
33 0 : fFlags |= kNaN;
34 0 : }
35 :
36 0 : void VisibleDigits::setInfinite() {
37 0 : fFlags |= kInfinite;
38 0 : }
39 :
40 0 : void VisibleDigits::clear() {
41 0 : fInterval.clear();
42 0 : fDigits.clear();
43 0 : fExponent = 0;
44 0 : fFlags = 0;
45 0 : fAbsIntValue = 0LL;
46 0 : fAbsIntValueSet = FALSE;
47 0 : fAbsDoubleValue = 0.0;
48 0 : fAbsDoubleValueSet = FALSE;
49 0 : }
50 :
51 0 : UBool VisibleDigits::isNegative() const {
52 0 : return (fFlags & kNegative);
53 : }
54 :
55 0 : UBool VisibleDigits::isNaN() const {
56 0 : return (fFlags & kNaN);
57 : }
58 :
59 0 : UBool VisibleDigits::isInfinite() const {
60 0 : return (fFlags & kInfinite);
61 : }
62 :
63 0 : int32_t VisibleDigits::getDigitByExponent(int32_t digitPos) const {
64 0 : if (digitPos < fExponent || digitPos >= fExponent + fDigits.length()) {
65 0 : return 0;
66 : }
67 0 : const char *ptr = fDigits.data();
68 0 : return ptr[digitPos - fExponent];
69 : }
70 :
71 0 : UBool VisibleDigits::isOverMaxDigits() const {
72 0 : return (fExponent + fDigits.length() > fInterval.getMostSignificantExclusive());
73 : }
74 :
75 0 : UBool VisibleDigits::isNaNOrInfinity() const {
76 0 : return (fFlags & (kInfinite | kNaN)) != 0;
77 : }
78 :
79 0 : double VisibleDigits::computeAbsDoubleValue() const {
80 : // Take care of NaN and infinity
81 0 : if (isNaN()) {
82 0 : return uprv_getNaN();
83 : }
84 0 : if (isInfinite()) {
85 0 : 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 0 : decNumber *numberPtr = &decNumberWithStorage.decNum;
94 :
95 0 : int32_t mostSig = fInterval.getMostSignificantExclusive();
96 0 : int32_t mostSigNonZero = fExponent + fDigits.length();
97 0 : int32_t end = mostSig > mostSigNonZero ? mostSigNonZero : mostSig;
98 0 : int32_t leastSig = fInterval.getLeastSignificantInclusive();
99 0 : int32_t start = leastSig > fExponent ? leastSig : fExponent;
100 0 : if (end <= start) {
101 0 : return 0.0;
102 : }
103 0 : if (start < end - (MAX_DBL_DIGITS+3)) {
104 0 : start = end - (MAX_DBL_DIGITS+3);
105 : }
106 0 : uint8_t *pos = numberPtr->lsu;
107 0 : const char *src = &(fDigits.data()[start - fExponent]);
108 0 : for (int32_t i = start; i < end; ++i) {
109 0 : *pos++ = (uint8_t) (*src++);
110 : }
111 0 : numberPtr->exponent = start;
112 0 : numberPtr->bits = 0;
113 0 : numberPtr->digits = end - start;
114 : char str[MAX_DBL_DIGITS+18];
115 0 : uprv_decNumberToString(numberPtr, str);
116 0 : U_ASSERT(uprv_strlen(str) < MAX_DBL_DIGITS+18);
117 0 : char *unused = NULL;
118 0 : return DigitList::decimalStrToDouble(str, &unused);
119 : }
120 :
121 0 : void VisibleDigits::getFixedDecimal(
122 : double &source, int64_t &intValue, int64_t &f, int64_t &t, int32_t &v, UBool &hasIntValue) const {
123 0 : source = 0.0;
124 0 : intValue = 0;
125 0 : f = 0;
126 0 : t = 0;
127 0 : v = 0;
128 0 : hasIntValue = FALSE;
129 0 : if (isNaNOrInfinity()) {
130 0 : return;
131 : }
132 :
133 : // source
134 0 : if (fAbsDoubleValueSet) {
135 0 : source = fAbsDoubleValue;
136 : } else {
137 0 : source = computeAbsDoubleValue();
138 : }
139 :
140 : // visible decimal digits
141 0 : v = fInterval.getFracDigitCount();
142 :
143 : // intValue
144 :
145 : // If we initialized from an int64 just use that instead of
146 : // calculating
147 0 : if (fAbsIntValueSet) {
148 0 : intValue = fAbsIntValue;
149 : } else {
150 0 : int32_t startPos = fInterval.getMostSignificantExclusive();
151 0 : if (startPos > 18) {
152 0 : startPos = 18;
153 : }
154 : // process the integer digits
155 0 : for (int32_t i = startPos - 1; i >= 0; --i) {
156 0 : intValue = intValue * 10LL + getDigitByExponent(i);
157 : }
158 0 : if (intValue == 0LL && startPos > 0) {
159 0 : intValue = 100000000000000000LL;
160 : }
161 : }
162 :
163 : // f (decimal digits)
164 : // skip over any leading 0's in fraction digits.
165 0 : int32_t idx = -1;
166 0 : 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 0 : for (int32_t i = idx; i >= -v && i > idx - 18; --i) {
172 0 : f = f * 10LL + getDigitByExponent(i);
173 : }
174 :
175 : // If we have no decimal digits, we don't have an integer value
176 0 : hasIntValue = (f == 0LL);
177 :
178 : // t (decimal digits without trailing zeros)
179 0 : t = f;
180 0 : while (t > 0 && t % 10LL == 0) {
181 0 : t /= 10;
182 : }
183 : }
184 :
185 : U_NAMESPACE_END
186 : #endif /* #if !UCONFIG_NO_FORMATTING */
|