]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/visibledigits.cpp
ICU-57166.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / visibledigits.cpp
CommitLineData
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
20static const int32_t kNegative = 1;
21static const int32_t kInfinite = 2;
22static const int32_t kNaN = 4;
23
24U_NAMESPACE_BEGIN
25
26void VisibleDigits::setNegative() {
27 fFlags |= kNegative;
28}
29
30void VisibleDigits::setNaN() {
31 fFlags |= kNaN;
32}
33
34void VisibleDigits::setInfinite() {
35 fFlags |= kInfinite;
36}
37
38void 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
49UBool VisibleDigits::isNegative() const {
50 return (fFlags & kNegative);
51}
52
53UBool VisibleDigits::isNaN() const {
54 return (fFlags & kNaN);
55}
56
57UBool VisibleDigits::isInfinite() const {
58 return (fFlags & kInfinite);
59}
60
61int32_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
69UBool VisibleDigits::isOverMaxDigits() const {
70 return (fExponent + fDigits.length() > fInterval.getMostSignificantExclusive());
71}
72
73UBool VisibleDigits::isNaNOrInfinity() const {
74 return (fFlags & (kInfinite | kNaN)) != 0;
75}
76
77double 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
123void 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
186U_NAMESPACE_END
187#endif /* #if !UCONFIG_NO_FORMATTING */