]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/visibledigits.cpp
ICU-59180.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / visibledigits.cpp
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 */