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(scaled
, -n
, digits
, status
)) {
243 digits
.fAbsDoubleValue
= fabs(value
);
244 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 if (scaled
== 0.0 && uprv_isNegative(scaled
)) {
248 digits
.setNegative();
253 // Oops have to use digit list
255 digitList
.set(value
);
256 return initVisibleDigits(digitList
, digits
, status
);
260 FixedPrecision::initVisibleDigits(
263 VisibleDigits
&digits
,
264 UErrorCode
&status
) const {
265 if (U_FAILURE(status
)) {
270 // Precompute fAbsIntValue if it is small enough, but we don't know yet
271 // if it will be valid.
272 UBool absIntValueComputed
= FALSE
;
273 if (mantissa
> -1000000000000000000LL /* -1e18 */
274 && mantissa
< 1000000000000000000LL /* 1e18 */) {
275 digits
.fAbsIntValue
= mantissa
;
276 if (digits
.fAbsIntValue
< 0) {
277 digits
.fAbsIntValue
= -digits
.fAbsIntValue
;
280 int32_t maxPower10Exp
= UPRV_LENGTHOF(gPower10
) - 1;
281 for (; i
> exponent
+ maxPower10Exp
; i
-= maxPower10Exp
) {
282 digits
.fAbsIntValue
/= gPower10
[maxPower10Exp
];
284 digits
.fAbsIntValue
/= gPower10
[i
- exponent
];
285 absIntValueComputed
= TRUE
;
288 getIntervalForZero(digits
.fInterval
);
289 digits
.fAbsIntValueSet
= absIntValueComputed
;
292 // be sure least significant digit is non zero
293 while (mantissa
% 10 == 0) {
298 digits
.fDigits
.append((char) -(mantissa
% -10), status
);
300 digits
.setNegative();
303 digits
.fDigits
.append((char) (mantissa
% 10), status
);
306 if (U_FAILURE(status
)) {
309 digits
.fExponent
= exponent
;
310 int32_t upperExponent
= exponent
+ digits
.fDigits
.length();
311 if (fFailIfOverMax
&& upperExponent
> fMax
.getIntDigitCount()) {
312 status
= U_ILLEGAL_ARGUMENT_ERROR
;
315 UBool roundingRequired
=
316 isRoundingRequired(upperExponent
, exponent
);
317 if (roundingRequired
) {
319 status
= U_FORMAT_INEXACT_ERROR
;
324 digits
.fInterval
.setLeastSignificantInclusive(exponent
);
325 digits
.fInterval
.setMostSignificantExclusive(upperExponent
);
326 getInterval(upperExponent
, digits
.fInterval
);
328 // The intValue we computed above is only valid if our visible digits
329 // doesn't exceed the maximum integer digits allowed.
330 digits
.fAbsIntValueSet
= absIntValueComputed
&& !digits
.isOverMaxDigits();
334 VisibleDigitsWithExponent
&
335 FixedPrecision::initVisibleDigitsWithExponent(
337 VisibleDigitsWithExponent
&digits
,
338 UErrorCode
&status
) const {
340 initVisibleDigits(value
, digits
.fMantissa
, status
);
344 VisibleDigitsWithExponent
&
345 FixedPrecision::initVisibleDigitsWithExponent(
347 VisibleDigitsWithExponent
&digits
,
348 UErrorCode
&status
) const {
350 initVisibleDigits(value
, digits
.fMantissa
, status
);
354 VisibleDigitsWithExponent
&
355 FixedPrecision::initVisibleDigitsWithExponent(
357 VisibleDigitsWithExponent
&digits
,
358 UErrorCode
&status
) const {
360 initVisibleDigits(value
, digits
.fMantissa
, status
);
364 ScientificPrecision::ScientificPrecision() : fMinExponentDigits(1) {
368 ScientificPrecision::round(DigitList
&value
, UErrorCode
&status
) const {
369 if (U_FAILURE(status
)) {
372 int32_t exponent
= value
.getScientificExponent(
373 fMantissa
.fMin
.getIntDigitCount(), getMultiplier());
374 return fMantissa
.round(value
, exponent
, status
);
378 ScientificPrecision::toScientific(DigitList
&value
) const {
379 return value
.toScientific(
380 fMantissa
.fMin
.getIntDigitCount(), getMultiplier());
384 ScientificPrecision::getMultiplier() const {
385 int32_t maxIntDigitCount
= fMantissa
.fMax
.getIntDigitCount();
386 if (maxIntDigitCount
== INT32_MAX
) {
390 maxIntDigitCount
- fMantissa
.fMin
.getIntDigitCount() + 1;
391 return (multiplier
< 1 ? 1 : multiplier
);
394 VisibleDigitsWithExponent
&
395 ScientificPrecision::initVisibleDigitsWithExponent(
397 VisibleDigitsWithExponent
&digits
,
398 UErrorCode
&status
) const {
399 if (U_FAILURE(status
)) {
403 if (FixedPrecision::handleNonNumeric(value
, digits
.fMantissa
)) {
406 value
.setRoundingMode(fMantissa
.fRoundingMode
);
407 int64_t exponent
= toScientific(round(value
, status
));
408 fMantissa
.initVisibleDigits(value
, digits
.fMantissa
, status
);
409 FixedPrecision exponentPrecision
;
410 exponentPrecision
.fMin
.setIntDigitCount(fMinExponentDigits
);
411 exponentPrecision
.initVisibleDigits(exponent
, digits
.fExponent
, status
);
412 digits
.fHasExponent
= TRUE
;
416 VisibleDigitsWithExponent
&
417 ScientificPrecision::initVisibleDigitsWithExponent(
419 VisibleDigitsWithExponent
&digits
,
420 UErrorCode
&status
) const {
421 if (U_FAILURE(status
)) {
425 digitList
.set(value
);
426 return initVisibleDigitsWithExponent(digitList
, digits
, status
);
429 VisibleDigitsWithExponent
&
430 ScientificPrecision::initVisibleDigitsWithExponent(
432 VisibleDigitsWithExponent
&digits
,
433 UErrorCode
&status
) const {
434 if (U_FAILURE(status
)) {
438 digitList
.set(value
);
439 return initVisibleDigitsWithExponent(digitList
, digits
, status
);
444 #endif /* #if !UCONFIG_NO_FORMATTING */