]> git.saurik.com Git - apple/icu.git/blame_incremental - icuSources/i18n/precision.cpp
ICU-62141.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / precision.cpp
... / ...
CommitLineData
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
22U_NAMESPACE_BEGIN
23
24static const int32_t gPower10[] = {1, 10, 100, 1000};
25
26FixedPrecision::FixedPrecision()
27 : fExactOnly(FALSE), fFailIfOverMax(FALSE), fRoundingMode(DecimalFormat::kRoundHalfEven) {
28 fMin.setIntDigitCount(1);
29 fMin.setFracDigitCount(0);
30}
31
32UBool
33FixedPrecision::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
48DigitList &
49FixedPrecision::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
88DigitInterval &
89FixedPrecision::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
98DigitInterval &
99FixedPrecision::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
110DigitInterval &
111FixedPrecision::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
130UBool
131FixedPrecision::isFastFormattable() const {
132 return (fMin.getFracDigitCount() == 0 && fSignificant.isNoConstraints() && fRoundingIncrement.isZero() && !fFailIfOverMax);
133}
134
135UBool
136FixedPrecision::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
151VisibleDigits &
152FixedPrecision::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
174VisibleDigits &
175FixedPrecision::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
200VisibleDigits &
201FixedPrecision::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
260UBool
261FixedPrecision::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
335VisibleDigitsWithExponent &
336FixedPrecision::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
345VisibleDigitsWithExponent &
346FixedPrecision::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
355VisibleDigitsWithExponent &
356FixedPrecision::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
365ScientificPrecision::ScientificPrecision() : fMinExponentDigits(1) {
366}
367
368DigitList &
369ScientificPrecision::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
378int32_t
379ScientificPrecision::toScientific(DigitList &value) const {
380 return value.toScientific(
381 fMantissa.fMin.getIntDigitCount(), getMultiplier());
382}
383
384int32_t
385ScientificPrecision::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
395VisibleDigitsWithExponent &
396ScientificPrecision::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
417VisibleDigitsWithExponent &
418ScientificPrecision::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.fFormatFullPrecision = digits.fMantissa.formatFullPrecision(); // Apples
427 digitList.set(value);
428 return initVisibleDigitsWithExponent(digitList, digits, status);
429}
430
431VisibleDigitsWithExponent &
432ScientificPrecision::initVisibleDigitsWithExponent(
433 int64_t value,
434 VisibleDigitsWithExponent &digits,
435 UErrorCode &status) const {
436 if (U_FAILURE(status)) {
437 return digits;
438 }
439 DigitList digitList;
440 digitList.set(value);
441 return initVisibleDigitsWithExponent(digitList, digits, status);
442}
443
444
445U_NAMESPACE_END
446#endif /* #if !UCONFIG_NO_FORMATTING */