1 // Copyright (C) 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 */