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