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