1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 * Copyright (C) 2015, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 * file name: precisison.cpp
12 #include "unicode/utypes.h"
14 #if !UCONFIG_NO_FORMATTING
17 #include "fmtableimp.h"
18 #include "precision.h"
20 #include "visibledigits.h"
24 static const int32_t gPower10
[] = {1, 10, 100, 1000};
26 FixedPrecision::FixedPrecision()
27 : fExactOnly(FALSE
), fFailIfOverMax(FALSE
), fRoundingMode(DecimalFormat::kRoundHalfEven
) {
28 fMin
.setIntDigitCount(1);
29 fMin
.setFracDigitCount(0);
33 FixedPrecision::isRoundingRequired(
34 int32_t upperExponent
, int32_t lowerExponent
) const {
35 int32_t leastSigAllowed
= fMax
.getLeastSignificantInclusive();
36 int32_t maxSignificantDigits
= fSignificant
.getMax();
38 if (maxSignificantDigits
== INT32_MAX
) {
39 roundDigit
= leastSigAllowed
;
41 int32_t limitDigit
= upperExponent
- maxSignificantDigits
;
43 limitDigit
> leastSigAllowed
? limitDigit
: leastSigAllowed
;
45 return (roundDigit
> lowerExponent
);
49 FixedPrecision::round(
50 DigitList
&value
, int32_t exponent
, UErrorCode
&status
) const {
51 if (U_FAILURE(status
)) {
54 value
.fContext
.status
&= ~DEC_Inexact
;
55 if (!fRoundingIncrement
.isZero()) {
57 value
.quantize(fRoundingIncrement
, status
);
59 DigitList
adjustedIncrement(fRoundingIncrement
);
60 adjustedIncrement
.shiftDecimalRight(exponent
);
61 value
.quantize(adjustedIncrement
, status
);
63 if (U_FAILURE(status
)) {
67 int32_t leastSig
= fMax
.getLeastSignificantInclusive();
68 if (leastSig
== INT32_MIN
) {
69 value
.round(fSignificant
.getMax());
71 value
.roundAtExponent(
73 fSignificant
.getMax());
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
;
89 FixedPrecision::getIntervalForZero(DigitInterval
&interval
) const {
91 if (fSignificant
.getMin() > 0) {
92 interval
.expandToContainDigit(interval
.getIntDigitCount() - fSignificant
.getMin());
94 interval
.shrinkToFitWithin(fMax
);
99 FixedPrecision::getInterval(
100 int32_t upperExponent
, DigitInterval
&interval
) const {
101 if (fSignificant
.getMin() > 0) {
102 interval
.expandToContainDigit(
103 upperExponent
- fSignificant
.getMin());
105 interval
.expandToContain(fMin
);
106 interval
.shrinkToFitWithin(fMax
);
111 FixedPrecision::getInterval(
112 const DigitList
&value
, DigitInterval
&interval
) const {
113 if (value
.isZero()) {
115 if (fSignificant
.getMin() > 0) {
116 interval
.expandToContainDigit(interval
.getIntDigitCount() - fSignificant
.getMin());
119 value
.getSmallestInterval(interval
);
120 if (fSignificant
.getMin() > 0) {
121 interval
.expandToContainDigit(
122 value
.getUpperExponent() - fSignificant
.getMin());
124 interval
.expandToContain(fMin
);
126 interval
.shrinkToFitWithin(fMax
);
131 FixedPrecision::isFastFormattable() const {
132 return (fMin
.getFracDigitCount() == 0 && fSignificant
.isNoConstraints() && fRoundingIncrement
.isZero() && !fFailIfOverMax
);
136 FixedPrecision::handleNonNumeric(DigitList
&value
, VisibleDigits
&digits
) {
141 if (value
.isInfinite()) {
142 digits
.setInfinite();
143 if (!value
.isPositive()) {
144 digits
.setNegative();
152 FixedPrecision::initVisibleDigits(
154 VisibleDigits
&digits
,
155 UErrorCode
&status
) const {
156 if (U_FAILURE(status
)) {
160 if (handleNonNumeric(value
, digits
)) {
163 if (!value
.isPositive()) {
164 digits
.setNegative();
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
);
175 FixedPrecision::initVisibleDigits(
177 VisibleDigits
&digits
,
178 UErrorCode
&status
) const {
179 if (U_FAILURE(status
)) {
182 if (!fRoundingIncrement
.isZero()) {
183 // If we have round increment, use digit list.
185 digitList
.set(value
);
186 return initVisibleDigits(digitList
, digits
, status
);
189 if (initVisibleDigits(value
, 0, digits
, status
)) {
190 digits
.fAbsDoubleValue
= fabs((double) value
);
191 digits
.fAbsDoubleValueSet
= U_SUCCESS(status
) && !digits
.isOverMaxDigits();
194 // Oops have to use digit list
196 digitList
.set(value
);
197 return initVisibleDigits(digitList
, digits
, status
);
201 FixedPrecision::initVisibleDigits(
203 VisibleDigits
&digits
,
204 UErrorCode
&status
) const {
205 if (U_FAILURE(status
)) {
209 if (uprv_isNaN(value
)) {
213 if (uprv_isPositiveInfinity(value
)) {
214 digits
.setInfinite();
217 if (uprv_isNegativeInfinity(value
)) {
218 digits
.setInfinite();
219 digits
.setNegative();
222 if (!fRoundingIncrement
.isZero()) {
223 // If we have round increment, use digit list.
225 digitList
.set(value
);
226 return initVisibleDigits(digitList
, digits
, status
);
228 // Try to find n such that value * 10^n is an integer
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
) {
236 if (scaled
== floor(scaled
)) {
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();
253 // Oops have to use digit list
255 digitList
.fFormatFullPrecision
= digits
.formatFullPrecision(); // Apple
256 digitList
.set(value
);
257 return initVisibleDigits(digitList
, digits
, status
);
261 FixedPrecision::initVisibleDigits(
264 VisibleDigits
&digits
,
265 UErrorCode
&status
) const {
266 if (U_FAILURE(status
)) {
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
;
281 int32_t maxPower10Exp
= UPRV_LENGTHOF(gPower10
) - 1;
282 for (; i
> exponent
+ maxPower10Exp
; i
-= maxPower10Exp
) {
283 digits
.fAbsIntValue
/= gPower10
[maxPower10Exp
];
285 digits
.fAbsIntValue
/= gPower10
[i
- exponent
];
286 absIntValueComputed
= TRUE
;
289 getIntervalForZero(digits
.fInterval
);
290 digits
.fAbsIntValueSet
= absIntValueComputed
;
293 // be sure least significant digit is non zero
294 while (mantissa
% 10 == 0) {
299 digits
.fDigits
.append((char) -(mantissa
% -10), status
);
301 digits
.setNegative();
304 digits
.fDigits
.append((char) (mantissa
% 10), status
);
307 if (U_FAILURE(status
)) {
310 digits
.fExponent
= exponent
;
311 int32_t upperExponent
= exponent
+ digits
.fDigits
.length();
312 if (fFailIfOverMax
&& upperExponent
> fMax
.getIntDigitCount()) {
313 status
= U_ILLEGAL_ARGUMENT_ERROR
;
316 UBool roundingRequired
=
317 isRoundingRequired(upperExponent
, exponent
);
318 if (roundingRequired
) {
320 status
= U_FORMAT_INEXACT_ERROR
;
325 digits
.fInterval
.setLeastSignificantInclusive(exponent
);
326 digits
.fInterval
.setMostSignificantExclusive(upperExponent
);
327 getInterval(upperExponent
, digits
.fInterval
);
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();
335 VisibleDigitsWithExponent
&
336 FixedPrecision::initVisibleDigitsWithExponent(
338 VisibleDigitsWithExponent
&digits
,
339 UErrorCode
&status
) const {
341 initVisibleDigits(value
, digits
.fMantissa
, status
);
345 VisibleDigitsWithExponent
&
346 FixedPrecision::initVisibleDigitsWithExponent(
348 VisibleDigitsWithExponent
&digits
,
349 UErrorCode
&status
) const {
351 initVisibleDigits(value
, digits
.fMantissa
, status
);
355 VisibleDigitsWithExponent
&
356 FixedPrecision::initVisibleDigitsWithExponent(
358 VisibleDigitsWithExponent
&digits
,
359 UErrorCode
&status
) const {
361 initVisibleDigits(value
, digits
.fMantissa
, status
);
365 ScientificPrecision::ScientificPrecision() : fMinExponentDigits(1) {
369 ScientificPrecision::round(DigitList
&value
, UErrorCode
&status
) const {
370 if (U_FAILURE(status
)) {
373 int32_t exponent
= value
.getScientificExponent(
374 fMantissa
.fMin
.getIntDigitCount(), getMultiplier());
375 return fMantissa
.round(value
, exponent
, status
);
379 ScientificPrecision::toScientific(DigitList
&value
) const {
380 return value
.toScientific(
381 fMantissa
.fMin
.getIntDigitCount(), getMultiplier());
385 ScientificPrecision::getMultiplier() const {
386 int32_t maxIntDigitCount
= fMantissa
.fMax
.getIntDigitCount();
387 if (maxIntDigitCount
== INT32_MAX
) {
391 maxIntDigitCount
- fMantissa
.fMin
.getIntDigitCount() + 1;
392 return (multiplier
< 1 ? 1 : multiplier
);
395 VisibleDigitsWithExponent
&
396 ScientificPrecision::initVisibleDigitsWithExponent(
398 VisibleDigitsWithExponent
&digits
,
399 UErrorCode
&status
) const {
400 if (U_FAILURE(status
)) {
404 if (FixedPrecision::handleNonNumeric(value
, digits
.fMantissa
)) {
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
;
417 VisibleDigitsWithExponent
&
418 ScientificPrecision::initVisibleDigitsWithExponent(
420 VisibleDigitsWithExponent
&digits
,
421 UErrorCode
&status
) const {
422 if (U_FAILURE(status
)) {
426 digitList
.set(value
);
427 return initVisibleDigitsWithExponent(digitList
, digits
, status
);
430 VisibleDigitsWithExponent
&
431 ScientificPrecision::initVisibleDigitsWithExponent(
433 VisibleDigitsWithExponent
&digits
,
434 UErrorCode
&status
) const {
435 if (U_FAILURE(status
)) {
439 digitList
.set(value
);
440 return initVisibleDigitsWithExponent(digitList
, digits
, status
);
445 #endif /* #if !UCONFIG_NO_FORMATTING */