2 * Copyright (C) 2015, International Business Machines
3 * Corporation and others. All Rights Reserved.
5 * file name: precisison.cpp
10 #include "unicode/utypes.h"
12 #if !UCONFIG_NO_FORMATTING
15 #include "fmtableimp.h"
16 #include "precision.h"
18 #include "visibledigits.h"
22 static const int32_t gPower10
[] = {1, 10, 100, 1000};
24 FixedPrecision::FixedPrecision()
25 : fExactOnly(FALSE
), fFailIfOverMax(FALSE
), fRoundingMode(DecimalFormat::kRoundHalfEven
) {
26 fMin
.setIntDigitCount(1);
27 fMin
.setFracDigitCount(0);
31 FixedPrecision::isRoundingRequired(
32 int32_t upperExponent
, int32_t lowerExponent
) const {
33 int32_t leastSigAllowed
= fMax
.getLeastSignificantInclusive();
34 int32_t maxSignificantDigits
= fSignificant
.getMax();
36 if (maxSignificantDigits
== INT32_MAX
) {
37 roundDigit
= leastSigAllowed
;
39 int32_t limitDigit
= upperExponent
- maxSignificantDigits
;
41 limitDigit
> leastSigAllowed
? limitDigit
: leastSigAllowed
;
43 return (roundDigit
> lowerExponent
);
47 FixedPrecision::round(
48 DigitList
&value
, int32_t exponent
, UErrorCode
&status
) const {
49 if (U_FAILURE(status
)) {
52 value
.fContext
.status
&= ~DEC_Inexact
;
53 if (!fRoundingIncrement
.isZero()) {
55 value
.quantize(fRoundingIncrement
, status
);
57 DigitList
adjustedIncrement(fRoundingIncrement
);
58 adjustedIncrement
.shiftDecimalRight(exponent
);
59 value
.quantize(adjustedIncrement
, status
);
61 if (U_FAILURE(status
)) {
65 int32_t leastSig
= fMax
.getLeastSignificantInclusive();
66 if (leastSig
== INT32_MIN
) {
67 value
.round(fSignificant
.getMax());
69 value
.roundAtExponent(
71 fSignificant
.getMax());
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
;
87 FixedPrecision::getIntervalForZero(DigitInterval
&interval
) const {
89 if (fSignificant
.getMin() > 0) {
90 interval
.expandToContainDigit(interval
.getIntDigitCount() - fSignificant
.getMin());
92 interval
.shrinkToFitWithin(fMax
);
97 FixedPrecision::getInterval(
98 int32_t upperExponent
, DigitInterval
&interval
) const {
99 if (fSignificant
.getMin() > 0) {
100 interval
.expandToContainDigit(
101 upperExponent
- fSignificant
.getMin());
103 interval
.expandToContain(fMin
);
104 interval
.shrinkToFitWithin(fMax
);
109 FixedPrecision::getInterval(
110 const DigitList
&value
, DigitInterval
&interval
) const {
111 if (value
.isZero()) {
113 if (fSignificant
.getMin() > 0) {
114 interval
.expandToContainDigit(interval
.getIntDigitCount() - fSignificant
.getMin());
117 value
.getSmallestInterval(interval
);
118 if (fSignificant
.getMin() > 0) {
119 interval
.expandToContainDigit(
120 value
.getUpperExponent() - fSignificant
.getMin());
122 interval
.expandToContain(fMin
);
124 interval
.shrinkToFitWithin(fMax
);
129 FixedPrecision::isFastFormattable() const {
130 return (fMin
.getFracDigitCount() == 0 && fSignificant
.isNoConstraints() && fRoundingIncrement
.isZero() && !fFailIfOverMax
);
134 FixedPrecision::handleNonNumeric(DigitList
&value
, VisibleDigits
&digits
) {
139 if (value
.isInfinite()) {
140 digits
.setInfinite();
141 if (!value
.isPositive()) {
142 digits
.setNegative();
150 FixedPrecision::initVisibleDigits(
152 VisibleDigits
&digits
,
153 UErrorCode
&status
) const {
154 if (U_FAILURE(status
)) {
158 if (handleNonNumeric(value
, digits
)) {
161 if (!value
.isPositive()) {
162 digits
.setNegative();
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
);
173 FixedPrecision::initVisibleDigits(
175 VisibleDigits
&digits
,
176 UErrorCode
&status
) const {
177 if (U_FAILURE(status
)) {
180 if (!fRoundingIncrement
.isZero()) {
181 // If we have round increment, use digit list.
183 digitList
.set(value
);
184 return initVisibleDigits(digitList
, digits
, status
);
187 if (initVisibleDigits(value
, 0, digits
, status
)) {
188 digits
.fAbsDoubleValue
= fabs((double) value
);
189 digits
.fAbsDoubleValueSet
= U_SUCCESS(status
) && !digits
.isOverMaxDigits();
192 // Oops have to use digit list
194 digitList
.set(value
);
195 return initVisibleDigits(digitList
, digits
, status
);
199 FixedPrecision::initVisibleDigits(
201 VisibleDigits
&digits
,
202 UErrorCode
&status
) const {
203 if (U_FAILURE(status
)) {
207 if (uprv_isNaN(value
)) {
211 if (uprv_isPositiveInfinity(value
)) {
212 digits
.setInfinite();
215 if (uprv_isNegativeInfinity(value
)) {
216 digits
.setInfinite();
217 digits
.setNegative();
220 if (!fRoundingIncrement
.isZero()) {
221 // If we have round increment, use digit list.
223 digitList
.set(value
);
224 return initVisibleDigits(digitList
, digits
, status
);
226 // Try to find n such that value * 10^n is an integer
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
) {
234 if (scaled
== floor(scaled
)) {
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();
251 // Oops have to use digit list
253 digitList
.set(value
);
254 return initVisibleDigits(digitList
, digits
, status
);
258 FixedPrecision::initVisibleDigits(
261 VisibleDigits
&digits
,
262 UErrorCode
&status
) const {
263 if (U_FAILURE(status
)) {
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
;
278 int32_t maxPower10Exp
= UPRV_LENGTHOF(gPower10
) - 1;
279 for (; i
> exponent
+ maxPower10Exp
; i
-= maxPower10Exp
) {
280 digits
.fAbsIntValue
/= gPower10
[maxPower10Exp
];
282 digits
.fAbsIntValue
/= gPower10
[i
- exponent
];
283 absIntValueComputed
= TRUE
;
286 getIntervalForZero(digits
.fInterval
);
287 digits
.fAbsIntValueSet
= absIntValueComputed
;
290 // be sure least significant digit is non zero
291 while (mantissa
% 10 == 0) {
296 digits
.fDigits
.append((char) -(mantissa
% -10), status
);
298 digits
.setNegative();
301 digits
.fDigits
.append((char) (mantissa
% 10), status
);
304 if (U_FAILURE(status
)) {
307 digits
.fExponent
= exponent
;
308 int32_t upperExponent
= exponent
+ digits
.fDigits
.length();
309 if (fFailIfOverMax
&& upperExponent
> fMax
.getIntDigitCount()) {
310 status
= U_ILLEGAL_ARGUMENT_ERROR
;
313 UBool roundingRequired
=
314 isRoundingRequired(upperExponent
, exponent
);
315 if (roundingRequired
) {
317 status
= U_FORMAT_INEXACT_ERROR
;
322 digits
.fInterval
.setLeastSignificantInclusive(exponent
);
323 digits
.fInterval
.setMostSignificantExclusive(upperExponent
);
324 getInterval(upperExponent
, digits
.fInterval
);
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();
332 VisibleDigitsWithExponent
&
333 FixedPrecision::initVisibleDigitsWithExponent(
335 VisibleDigitsWithExponent
&digits
,
336 UErrorCode
&status
) const {
338 initVisibleDigits(value
, digits
.fMantissa
, status
);
342 VisibleDigitsWithExponent
&
343 FixedPrecision::initVisibleDigitsWithExponent(
345 VisibleDigitsWithExponent
&digits
,
346 UErrorCode
&status
) const {
348 initVisibleDigits(value
, digits
.fMantissa
, status
);
352 VisibleDigitsWithExponent
&
353 FixedPrecision::initVisibleDigitsWithExponent(
355 VisibleDigitsWithExponent
&digits
,
356 UErrorCode
&status
) const {
358 initVisibleDigits(value
, digits
.fMantissa
, status
);
362 ScientificPrecision::ScientificPrecision() : fMinExponentDigits(1) {
366 ScientificPrecision::round(DigitList
&value
, UErrorCode
&status
) const {
367 if (U_FAILURE(status
)) {
370 int32_t exponent
= value
.getScientificExponent(
371 fMantissa
.fMin
.getIntDigitCount(), getMultiplier());
372 return fMantissa
.round(value
, exponent
, status
);
376 ScientificPrecision::toScientific(DigitList
&value
) const {
377 return value
.toScientific(
378 fMantissa
.fMin
.getIntDigitCount(), getMultiplier());
382 ScientificPrecision::getMultiplier() const {
383 int32_t maxIntDigitCount
= fMantissa
.fMax
.getIntDigitCount();
384 if (maxIntDigitCount
== INT32_MAX
) {
388 maxIntDigitCount
- fMantissa
.fMin
.getIntDigitCount() + 1;
389 return (multiplier
< 1 ? 1 : multiplier
);
392 VisibleDigitsWithExponent
&
393 ScientificPrecision::initVisibleDigitsWithExponent(
395 VisibleDigitsWithExponent
&digits
,
396 UErrorCode
&status
) const {
397 if (U_FAILURE(status
)) {
401 if (FixedPrecision::handleNonNumeric(value
, digits
.fMantissa
)) {
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
;
414 VisibleDigitsWithExponent
&
415 ScientificPrecision::initVisibleDigitsWithExponent(
417 VisibleDigitsWithExponent
&digits
,
418 UErrorCode
&status
) const {
419 if (U_FAILURE(status
)) {
423 digitList
.set(value
);
424 return initVisibleDigitsWithExponent(digitList
, digits
, status
);
427 VisibleDigitsWithExponent
&
428 ScientificPrecision::initVisibleDigitsWithExponent(
430 VisibleDigitsWithExponent
&digits
,
431 UErrorCode
&status
) const {
432 if (U_FAILURE(status
)) {
436 digitList
.set(value
);
437 return initVisibleDigitsWithExponent(digitList
, digits
, status
);
442 #endif /* #if !UCONFIG_NO_FORMATTING */