1 /*
2 * Copyright (C) 2015, International Business Machines
3 * Corporation and others. All Rights Reserved.
4 *
5 * file name: precisison.cpp
6 */
7
8 #include <math.h>
9
10 #include "unicode/utypes.h"
11
12 #if !UCONFIG_NO_FORMATTING
13
14 #include "digitlst.h"
15 #include "fmtableimp.h"
16 #include "precision.h"
17 #include "putilimp.h"
18 #include "visibledigits.h"
19
20 U_NAMESPACE_BEGIN
21
22 static const int32_t gPower10[] = {1, 10, 100, 1000};
23
FixedPrecision()24 FixedPrecision::FixedPrecision()
25 : fExactOnly(FALSE), fFailIfOverMax(FALSE), fRoundingMode(DecimalFormat::kRoundHalfEven) {
26 fMin.setIntDigitCount(1);
27 fMin.setFracDigitCount(0);
28 }
29
30 UBool
isRoundingRequired(int32_t upperExponent,int32_t lowerExponent) const31 FixedPrecision::isRoundingRequired(
32 int32_t upperExponent, int32_t lowerExponent) const {
33 int32_t leastSigAllowed = fMax.getLeastSignificantInclusive();
34 int32_t maxSignificantDigits = fSignificant.getMax();
35 int32_t roundDigit;
36 if (maxSignificantDigits == INT32_MAX) {
37 roundDigit = leastSigAllowed;
38 } else {
39 int32_t limitDigit = upperExponent - maxSignificantDigits;
40 roundDigit =
41 limitDigit > leastSigAllowed ? limitDigit : leastSigAllowed;
42 }
43 return (roundDigit > lowerExponent);
44 }
45
46 DigitList &
round(DigitList & value,int32_t exponent,UErrorCode & status) const47 FixedPrecision::round(
48 DigitList &value, int32_t exponent, UErrorCode &status) const {
49 if (U_FAILURE(status)) {
50 return value;
51 }
52 value .fContext.status &= ~DEC_Inexact;
53 if (!fRoundingIncrement.isZero()) {
54 if (exponent == 0) {
55 value.quantize(fRoundingIncrement, status);
56 } else {
57 DigitList adjustedIncrement(fRoundingIncrement);
58 adjustedIncrement.shiftDecimalRight(exponent);
59 value.quantize(adjustedIncrement, status);
60 }
61 if (U_FAILURE(status)) {
62 return value;
63 }
64 }
65 int32_t leastSig = fMax.getLeastSignificantInclusive();
66 if (leastSig == INT32_MIN) {
67 value.round(fSignificant.getMax());
68 } else {
69 value.roundAtExponent(
70 exponent + leastSig,
71 fSignificant.getMax());
72 }
73 if (fExactOnly && (value.fContext.status & DEC_Inexact)) {
74 status = U_FORMAT_INEXACT_ERROR;
75 } else if (fFailIfOverMax) {
76 // Smallest interval for value stored in interval
77 DigitInterval interval;
78 value.getSmallestInterval(interval);
79 if (fMax.getIntDigitCount() < interval.getIntDigitCount()) {
80 status = U_ILLEGAL_ARGUMENT_ERROR;
81 }
82 }
83 return value;
84 }
85
86 DigitInterval &
getIntervalForZero(DigitInterval & interval) const87 FixedPrecision::getIntervalForZero(DigitInterval &interval) const {
88 interval = fMin;
89 if (fSignificant.getMin() > 0) {
90 interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin());
91 }
92 interval.shrinkToFitWithin(fMax);
93 return interval;
94 }
95
96 DigitInterval &
getInterval(int32_t upperExponent,DigitInterval & interval) const97 FixedPrecision::getInterval(
98 int32_t upperExponent, DigitInterval &interval) const {
99 if (fSignificant.getMin() > 0) {
100 interval.expandToContainDigit(
101 upperExponent - fSignificant.getMin());
102 }
103 interval.expandToContain(fMin);
104 interval.shrinkToFitWithin(fMax);
105 return interval;
106 }
107
108 DigitInterval &
getInterval(const DigitList & value,DigitInterval & interval) const109 FixedPrecision::getInterval(
110 const DigitList &value, DigitInterval &interval) const {
111 if (value.isZero()) {
112 interval = fMin;
113 if (fSignificant.getMin() > 0) {
114 interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin());
115 }
116 } else {
117 value.getSmallestInterval(interval);
118 if (fSignificant.getMin() > 0) {
119 interval.expandToContainDigit(
120 value.getUpperExponent() - fSignificant.getMin());
121 }
122 interval.expandToContain(fMin);
123 }
124 interval.shrinkToFitWithin(fMax);
125 return interval;
126 }
127
128 UBool
isFastFormattable() const129 FixedPrecision::isFastFormattable() const {
130 return (fMin.getFracDigitCount() == 0 && fSignificant.isNoConstraints() && fRoundingIncrement.isZero() && !fFailIfOverMax);
131 }
132
133 UBool
handleNonNumeric(DigitList & value,VisibleDigits & digits)134 FixedPrecision::handleNonNumeric(DigitList &value, VisibleDigits &digits) {
135 if (value.isNaN()) {
136 digits.setNaN();
137 return TRUE;
138 }
139 if (value.isInfinite()) {
140 digits.setInfinite();
141 if (!value.isPositive()) {
142 digits.setNegative();
143 }
144 return TRUE;
145 }
146 return FALSE;
147 }
148
149 VisibleDigits &
initVisibleDigits(DigitList & value,VisibleDigits & digits,UErrorCode & status) const150 FixedPrecision::initVisibleDigits(
151 DigitList &value,
152 VisibleDigits &digits,
153 UErrorCode &status) const {
154 if (U_FAILURE(status)) {
155 return digits;
156 }
157 digits.clear();
158 if (handleNonNumeric(value, digits)) {
159 return digits;
160 }
161 if (!value.isPositive()) {
162 digits.setNegative();
163 }
164 value.setRoundingMode(fRoundingMode);
165 round(value, 0, status);
166 getInterval(value, digits.fInterval);
167 digits.fExponent = value.getLowerExponent();
168 value.appendDigitsTo(digits.fDigits, status);
169 return digits;
170 }
171
172 VisibleDigits &
initVisibleDigits(int64_t value,VisibleDigits & digits,UErrorCode & status) const173 FixedPrecision::initVisibleDigits(
174 int64_t value,
175 VisibleDigits &digits,
176 UErrorCode &status) const {
177 if (U_FAILURE(status)) {
178 return digits;
179 }
180 if (!fRoundingIncrement.isZero()) {
181 // If we have round increment, use digit list.
182 DigitList digitList;
183 digitList.set(value);
184 return initVisibleDigits(digitList, digits, status);
185 }
186 // Try fast path
187 if (initVisibleDigits(value, 0, digits, status)) {
188 digits.fAbsDoubleValue = fabs((double) value);
189 digits.fAbsDoubleValueSet = U_SUCCESS(status) && !digits.isOverMaxDigits();
190 return digits;
191 }
192 // Oops have to use digit list
193 DigitList digitList;
194 digitList.set(value);
195 return initVisibleDigits(digitList, digits, status);
196 }
197
198 VisibleDigits &
initVisibleDigits(double value,VisibleDigits & digits,UErrorCode & status) const199 FixedPrecision::initVisibleDigits(
200 double value,
201 VisibleDigits &digits,
202 UErrorCode &status) const {
203 if (U_FAILURE(status)) {
204 return digits;
205 }
206 digits.clear();
207 if (uprv_isNaN(value)) {
208 digits.setNaN();
209 return digits;
210 }
211 if (uprv_isPositiveInfinity(value)) {
212 digits.setInfinite();
213 return digits;
214 }
215 if (uprv_isNegativeInfinity(value)) {
216 digits.setInfinite();
217 digits.setNegative();
218 return digits;
219 }
220 if (!fRoundingIncrement.isZero()) {
221 // If we have round increment, use digit list.
222 DigitList digitList;
223 digitList.set(value);
224 return initVisibleDigits(digitList, digits, status);
225 }
226 // Try to find n such that value * 10^n is an integer
227 int32_t n = -1;
228 double scaled;
229 for (int32_t i = 0; i < UPRV_LENGTHOF(gPower10); ++i) {
230 scaled = value * gPower10[i];
231 if (scaled > MAX_INT64_IN_DOUBLE || scaled < -MAX_INT64_IN_DOUBLE) {
232 break;
233 }
234 if (scaled == floor(scaled)) {
235 n = i;
236 break;
237 }
238 }
239 // Try fast path
240 if (n >= 0 && initVisibleDigits(scaled, -n, digits, status)) {
241 digits.fAbsDoubleValue = fabs(value);
242 digits.fAbsDoubleValueSet = U_SUCCESS(status) && !digits.isOverMaxDigits();
243 // Adjust for negative 0 becuase when we cast to an int64,
244 // negative 0 becomes positive 0.
245 if (scaled == 0.0 && uprv_isNegative(scaled)) {
246 digits.setNegative();
247 }
248 return digits;
249 }
250
251 // Oops have to use digit list
252 DigitList digitList;
253 digitList.set(value);
254 return initVisibleDigits(digitList, digits, status);
255 }
256
257 UBool
initVisibleDigits(int64_t mantissa,int32_t exponent,VisibleDigits & digits,UErrorCode & status) const258 FixedPrecision::initVisibleDigits(
259 int64_t mantissa,
260 int32_t exponent,
261 VisibleDigits &digits,
262 UErrorCode &status) const {
263 if (U_FAILURE(status)) {
264 return TRUE;
265 }
266 digits.clear();
267
268 // Precompute fAbsIntValue if it is small enough, but we don't know yet
269 // if it will be valid.
270 UBool absIntValueComputed = FALSE;
271 if (mantissa > -1000000000000000000LL /* -1e18 */
272 && mantissa < 1000000000000000000LL /* 1e18 */) {
273 digits.fAbsIntValue = mantissa;
274 if (digits.fAbsIntValue < 0) {
275 digits.fAbsIntValue = -digits.fAbsIntValue;
276 }
277 int32_t i = 0;
278 int32_t maxPower10Exp = UPRV_LENGTHOF(gPower10) - 1;
279 for (; i > exponent + maxPower10Exp; i -= maxPower10Exp) {
280 digits.fAbsIntValue /= gPower10[maxPower10Exp];
281 }
282 digits.fAbsIntValue /= gPower10[i - exponent];
283 absIntValueComputed = TRUE;
284 }
285 if (mantissa == 0) {
286 getIntervalForZero(digits.fInterval);
287 digits.fAbsIntValueSet = absIntValueComputed;
288 return TRUE;
289 }
290 // be sure least significant digit is non zero
291 while (mantissa % 10 == 0) {
292 mantissa /= 10;
293 ++exponent;
294 }
295 if (mantissa < 0) {
296 digits.fDigits.append((char) -(mantissa % -10), status);
297 mantissa /= -10;
298 digits.setNegative();
299 }
300 while (mantissa) {
301 digits.fDigits.append((char) (mantissa % 10), status);
302 mantissa /= 10;
303 }
304 if (U_FAILURE(status)) {
305 return TRUE;
306 }
307 digits.fExponent = exponent;
308 int32_t upperExponent = exponent + digits.fDigits.length();
309 if (fFailIfOverMax && upperExponent > fMax.getIntDigitCount()) {
310 status = U_ILLEGAL_ARGUMENT_ERROR;
311 return TRUE;
312 }
313 UBool roundingRequired =
314 isRoundingRequired(upperExponent, exponent);
315 if (roundingRequired) {
316 if (fExactOnly) {
317 status = U_FORMAT_INEXACT_ERROR;
318 return TRUE;
319 }
320 return FALSE;
321 }
322 digits.fInterval.setLeastSignificantInclusive(exponent);
323 digits.fInterval.setMostSignificantExclusive(upperExponent);
324 getInterval(upperExponent, digits.fInterval);
325
326 // The intValue we computed above is only valid if our visible digits
327 // doesn't exceed the maximum integer digits allowed.
328 digits.fAbsIntValueSet = absIntValueComputed && !digits.isOverMaxDigits();
329 return TRUE;
330 }
331
332 VisibleDigitsWithExponent &
initVisibleDigitsWithExponent(DigitList & value,VisibleDigitsWithExponent & digits,UErrorCode & status) const333 FixedPrecision::initVisibleDigitsWithExponent(
334 DigitList &value,
335 VisibleDigitsWithExponent &digits,
336 UErrorCode &status) const {
337 digits.clear();
338 initVisibleDigits(value, digits.fMantissa, status);
339 return digits;
340 }
341
342 VisibleDigitsWithExponent &
initVisibleDigitsWithExponent(double value,VisibleDigitsWithExponent & digits,UErrorCode & status) const343 FixedPrecision::initVisibleDigitsWithExponent(
344 double value,
345 VisibleDigitsWithExponent &digits,
346 UErrorCode &status) const {
347 digits.clear();
348 initVisibleDigits(value, digits.fMantissa, status);
349 return digits;
350 }
351
352 VisibleDigitsWithExponent &
initVisibleDigitsWithExponent(int64_t value,VisibleDigitsWithExponent & digits,UErrorCode & status) const353 FixedPrecision::initVisibleDigitsWithExponent(
354 int64_t value,
355 VisibleDigitsWithExponent &digits,
356 UErrorCode &status) const {
357 digits.clear();
358 initVisibleDigits(value, digits.fMantissa, status);
359 return digits;
360 }
361
ScientificPrecision()362 ScientificPrecision::ScientificPrecision() : fMinExponentDigits(1) {
363 }
364
365 DigitList &
round(DigitList & value,UErrorCode & status) const366 ScientificPrecision::round(DigitList &value, UErrorCode &status) const {
367 if (U_FAILURE(status)) {
368 return value;
369 }
370 int32_t exponent = value.getScientificExponent(
371 fMantissa.fMin.getIntDigitCount(), getMultiplier());
372 return fMantissa.round(value, exponent, status);
373 }
374
375 int32_t
toScientific(DigitList & value) const376 ScientificPrecision::toScientific(DigitList &value) const {
377 return value.toScientific(
378 fMantissa.fMin.getIntDigitCount(), getMultiplier());
379 }
380
381 int32_t
getMultiplier() const382 ScientificPrecision::getMultiplier() const {
383 int32_t maxIntDigitCount = fMantissa.fMax.getIntDigitCount();
384 if (maxIntDigitCount == INT32_MAX) {
385 return 1;
386 }
387 int32_t multiplier =
388 maxIntDigitCount - fMantissa.fMin.getIntDigitCount() + 1;
389 return (multiplier < 1 ? 1 : multiplier);
390 }
391
392 VisibleDigitsWithExponent &
initVisibleDigitsWithExponent(DigitList & value,VisibleDigitsWithExponent & digits,UErrorCode & status) const393 ScientificPrecision::initVisibleDigitsWithExponent(
394 DigitList &value,
395 VisibleDigitsWithExponent &digits,
396 UErrorCode &status) const {
397 if (U_FAILURE(status)) {
398 return digits;
399 }
400 digits.clear();
401 if (FixedPrecision::handleNonNumeric(value, digits.fMantissa)) {
402 return digits;
403 }
404 value.setRoundingMode(fMantissa.fRoundingMode);
405 int64_t exponent = toScientific(round(value, status));
406 fMantissa.initVisibleDigits(value, digits.fMantissa, status);
407 FixedPrecision exponentPrecision;
408 exponentPrecision.fMin.setIntDigitCount(fMinExponentDigits);
409 exponentPrecision.initVisibleDigits(exponent, digits.fExponent, status);
410 digits.fHasExponent = TRUE;
411 return digits;
412 }
413
414 VisibleDigitsWithExponent &
initVisibleDigitsWithExponent(double value,VisibleDigitsWithExponent & digits,UErrorCode & status) const415 ScientificPrecision::initVisibleDigitsWithExponent(
416 double value,
417 VisibleDigitsWithExponent &digits,
418 UErrorCode &status) const {
419 if (U_FAILURE(status)) {
420 return digits;
421 }
422 DigitList digitList;
423 digitList.set(value);
424 return initVisibleDigitsWithExponent(digitList, digits, status);
425 }
426
427 VisibleDigitsWithExponent &
initVisibleDigitsWithExponent(int64_t value,VisibleDigitsWithExponent & digits,UErrorCode & status) const428 ScientificPrecision::initVisibleDigitsWithExponent(
429 int64_t value,
430 VisibleDigitsWithExponent &digits,
431 UErrorCode &status) const {
432 if (U_FAILURE(status)) {
433 return digits;
434 }
435 DigitList digitList;
436 digitList.set(value);
437 return initVisibleDigitsWithExponent(digitList, digits, status);
438 }
439
440
441 U_NAMESPACE_END
442 #endif /* #if !UCONFIG_NO_FORMATTING */
443