]>
Commit | Line | Data |
---|---|---|
2ca993e8 A |
1 | /* |
2 | * Copyright (C) 2015, International Business Machines | |
3 | * Corporation and others. All Rights Reserved. | |
4 | * | |
5 | * file name: precisison.cpp | |
6 | */ | |
7 | ||
8 | #include <math.h> | |
9 | ||
10 | #include "unicode/utypes.h" | |
11 | ||
12 | #if !UCONFIG_NO_FORMATTING | |
13 | ||
14 | #include "digitlst.h" | |
15 | #include "fmtableimp.h" | |
16 | #include "precision.h" | |
17 | #include "putilimp.h" | |
18 | #include "visibledigits.h" | |
19 | ||
20 | U_NAMESPACE_BEGIN | |
21 | ||
22 | static const int32_t gPower10[] = {1, 10, 100, 1000}; | |
23 | ||
24 | FixedPrecision::FixedPrecision() | |
25 | : fExactOnly(FALSE), fFailIfOverMax(FALSE), fRoundingMode(DecimalFormat::kRoundHalfEven) { | |
26 | fMin.setIntDigitCount(1); | |
27 | fMin.setFracDigitCount(0); | |
28 | } | |
29 | ||
30 | UBool | |
31 | FixedPrecision::isRoundingRequired( | |
32 | int32_t upperExponent, int32_t lowerExponent) const { | |
33 | int32_t leastSigAllowed = fMax.getLeastSignificantInclusive(); | |
34 | int32_t maxSignificantDigits = fSignificant.getMax(); | |
35 | int32_t roundDigit; | |
36 | if (maxSignificantDigits == INT32_MAX) { | |
37 | roundDigit = leastSigAllowed; | |
38 | } else { | |
39 | int32_t limitDigit = upperExponent - maxSignificantDigits; | |
40 | roundDigit = | |
41 | limitDigit > leastSigAllowed ? limitDigit : leastSigAllowed; | |
42 | } | |
43 | return (roundDigit > lowerExponent); | |
44 | } | |
45 | ||
46 | DigitList & | |
47 | FixedPrecision::round( | |
48 | DigitList &value, int32_t exponent, UErrorCode &status) const { | |
49 | if (U_FAILURE(status)) { | |
50 | return value; | |
51 | } | |
52 | value .fContext.status &= ~DEC_Inexact; | |
53 | if (!fRoundingIncrement.isZero()) { | |
54 | if (exponent == 0) { | |
55 | value.quantize(fRoundingIncrement, status); | |
56 | } else { | |
57 | DigitList adjustedIncrement(fRoundingIncrement); | |
58 | adjustedIncrement.shiftDecimalRight(exponent); | |
59 | value.quantize(adjustedIncrement, status); | |
60 | } | |
61 | if (U_FAILURE(status)) { | |
62 | return value; | |
63 | } | |
64 | } | |
65 | int32_t leastSig = fMax.getLeastSignificantInclusive(); | |
66 | if (leastSig == INT32_MIN) { | |
67 | value.round(fSignificant.getMax()); | |
68 | } else { | |
69 | value.roundAtExponent( | |
70 | exponent + leastSig, | |
71 | fSignificant.getMax()); | |
72 | } | |
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; | |
81 | } | |
82 | } | |
83 | return value; | |
84 | } | |
85 | ||
86 | DigitInterval & | |
87 | FixedPrecision::getIntervalForZero(DigitInterval &interval) const { | |
88 | interval = fMin; | |
89 | if (fSignificant.getMin() > 0) { | |
90 | interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin()); | |
91 | } | |
92 | interval.shrinkToFitWithin(fMax); | |
93 | return interval; | |
94 | } | |
95 | ||
96 | DigitInterval & | |
97 | FixedPrecision::getInterval( | |
98 | int32_t upperExponent, DigitInterval &interval) const { | |
99 | if (fSignificant.getMin() > 0) { | |
100 | interval.expandToContainDigit( | |
101 | upperExponent - fSignificant.getMin()); | |
102 | } | |
103 | interval.expandToContain(fMin); | |
104 | interval.shrinkToFitWithin(fMax); | |
105 | return interval; | |
106 | } | |
107 | ||
108 | DigitInterval & | |
109 | FixedPrecision::getInterval( | |
110 | const DigitList &value, DigitInterval &interval) const { | |
111 | if (value.isZero()) { | |
112 | interval = fMin; | |
113 | if (fSignificant.getMin() > 0) { | |
114 | interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin()); | |
115 | } | |
116 | } else { | |
117 | value.getSmallestInterval(interval); | |
118 | if (fSignificant.getMin() > 0) { | |
119 | interval.expandToContainDigit( | |
120 | value.getUpperExponent() - fSignificant.getMin()); | |
121 | } | |
122 | interval.expandToContain(fMin); | |
123 | } | |
124 | interval.shrinkToFitWithin(fMax); | |
125 | return interval; | |
126 | } | |
127 | ||
128 | UBool | |
129 | FixedPrecision::isFastFormattable() const { | |
130 | return (fMin.getFracDigitCount() == 0 && fSignificant.isNoConstraints() && fRoundingIncrement.isZero() && !fFailIfOverMax); | |
131 | } | |
132 | ||
133 | UBool | |
134 | FixedPrecision::handleNonNumeric(DigitList &value, VisibleDigits &digits) { | |
135 | if (value.isNaN()) { | |
136 | digits.setNaN(); | |
137 | return TRUE; | |
138 | } | |
139 | if (value.isInfinite()) { | |
140 | digits.setInfinite(); | |
141 | if (!value.isPositive()) { | |
142 | digits.setNegative(); | |
143 | } | |
144 | return TRUE; | |
145 | } | |
146 | return FALSE; | |
147 | } | |
148 | ||
149 | VisibleDigits & | |
150 | FixedPrecision::initVisibleDigits( | |
151 | DigitList &value, | |
152 | VisibleDigits &digits, | |
153 | UErrorCode &status) const { | |
154 | if (U_FAILURE(status)) { | |
155 | return digits; | |
156 | } | |
157 | digits.clear(); | |
158 | if (handleNonNumeric(value, digits)) { | |
159 | return digits; | |
160 | } | |
161 | if (!value.isPositive()) { | |
162 | digits.setNegative(); | |
163 | } | |
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); | |
169 | return digits; | |
170 | } | |
171 | ||
172 | VisibleDigits & | |
173 | FixedPrecision::initVisibleDigits( | |
174 | int64_t value, | |
175 | VisibleDigits &digits, | |
176 | UErrorCode &status) const { | |
177 | if (U_FAILURE(status)) { | |
178 | return digits; | |
179 | } | |
180 | if (!fRoundingIncrement.isZero()) { | |
181 | // If we have round increment, use digit list. | |
182 | DigitList digitList; | |
183 | digitList.set(value); | |
184 | return initVisibleDigits(digitList, digits, status); | |
185 | } | |
186 | // Try fast path | |
187 | if (initVisibleDigits(value, 0, digits, status)) { | |
188 | digits.fAbsDoubleValue = fabs((double) value); | |
189 | digits.fAbsDoubleValueSet = U_SUCCESS(status) && !digits.isOverMaxDigits(); | |
190 | return digits; | |
191 | } | |
192 | // Oops have to use digit list | |
193 | DigitList digitList; | |
194 | digitList.set(value); | |
195 | return initVisibleDigits(digitList, digits, status); | |
196 | } | |
197 | ||
198 | VisibleDigits & | |
199 | FixedPrecision::initVisibleDigits( | |
200 | double value, | |
201 | VisibleDigits &digits, | |
202 | UErrorCode &status) const { | |
203 | if (U_FAILURE(status)) { | |
204 | return digits; | |
205 | } | |
206 | digits.clear(); | |
207 | if (uprv_isNaN(value)) { | |
208 | digits.setNaN(); | |
209 | return digits; | |
210 | } | |
211 | if (uprv_isPositiveInfinity(value)) { | |
212 | digits.setInfinite(); | |
213 | return digits; | |
214 | } | |
215 | if (uprv_isNegativeInfinity(value)) { | |
216 | digits.setInfinite(); | |
217 | digits.setNegative(); | |
218 | return digits; | |
219 | } | |
220 | if (!fRoundingIncrement.isZero()) { | |
221 | // If we have round increment, use digit list. | |
222 | DigitList digitList; | |
223 | digitList.set(value); | |
224 | return initVisibleDigits(digitList, digits, status); | |
225 | } | |
226 | // Try to find n such that value * 10^n is an integer | |
227 | int32_t n = -1; | |
228 | double scaled; | |
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) { | |
232 | break; | |
233 | } | |
234 | if (scaled == floor(scaled)) { | |
235 | n = i; | |
236 | break; | |
237 | } | |
238 | } | |
239 | // Try fast path | |
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(); | |
247 | } | |
248 | return digits; | |
249 | } | |
250 | ||
251 | // Oops have to use digit list | |
252 | DigitList digitList; | |
253 | digitList.set(value); | |
254 | return initVisibleDigits(digitList, digits, status); | |
255 | } | |
256 | ||
257 | UBool | |
258 | FixedPrecision::initVisibleDigits( | |
259 | int64_t mantissa, | |
260 | int32_t exponent, | |
261 | VisibleDigits &digits, | |
262 | UErrorCode &status) const { | |
263 | if (U_FAILURE(status)) { | |
264 | return TRUE; | |
265 | } | |
266 | digits.clear(); | |
267 | ||
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; | |
276 | } | |
277 | int32_t i = 0; | |
278 | int32_t maxPower10Exp = UPRV_LENGTHOF(gPower10) - 1; | |
279 | for (; i > exponent + maxPower10Exp; i -= maxPower10Exp) { | |
280 | digits.fAbsIntValue /= gPower10[maxPower10Exp]; | |
281 | } | |
282 | digits.fAbsIntValue /= gPower10[i - exponent]; | |
283 | absIntValueComputed = TRUE; | |
284 | } | |
285 | if (mantissa == 0) { | |
286 | getIntervalForZero(digits.fInterval); | |
287 | digits.fAbsIntValueSet = absIntValueComputed; | |
288 | return TRUE; | |
289 | } | |
290 | // be sure least significant digit is non zero | |
291 | while (mantissa % 10 == 0) { | |
292 | mantissa /= 10; | |
293 | ++exponent; | |
294 | } | |
295 | if (mantissa < 0) { | |
296 | digits.fDigits.append((char) -(mantissa % -10), status); | |
297 | mantissa /= -10; | |
298 | digits.setNegative(); | |
299 | } | |
300 | while (mantissa) { | |
301 | digits.fDigits.append((char) (mantissa % 10), status); | |
302 | mantissa /= 10; | |
303 | } | |
304 | if (U_FAILURE(status)) { | |
305 | return TRUE; | |
306 | } | |
307 | digits.fExponent = exponent; | |
308 | int32_t upperExponent = exponent + digits.fDigits.length(); | |
309 | if (fFailIfOverMax && upperExponent > fMax.getIntDigitCount()) { | |
310 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
311 | return TRUE; | |
312 | } | |
313 | UBool roundingRequired = | |
314 | isRoundingRequired(upperExponent, exponent); | |
315 | if (roundingRequired) { | |
316 | if (fExactOnly) { | |
317 | status = U_FORMAT_INEXACT_ERROR; | |
318 | return TRUE; | |
319 | } | |
320 | return FALSE; | |
321 | } | |
322 | digits.fInterval.setLeastSignificantInclusive(exponent); | |
323 | digits.fInterval.setMostSignificantExclusive(upperExponent); | |
324 | getInterval(upperExponent, digits.fInterval); | |
325 | ||
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(); | |
329 | return TRUE; | |
330 | } | |
331 | ||
332 | VisibleDigitsWithExponent & | |
333 | FixedPrecision::initVisibleDigitsWithExponent( | |
334 | DigitList &value, | |
335 | VisibleDigitsWithExponent &digits, | |
336 | UErrorCode &status) const { | |
337 | digits.clear(); | |
338 | initVisibleDigits(value, digits.fMantissa, status); | |
339 | return digits; | |
340 | } | |
341 | ||
342 | VisibleDigitsWithExponent & | |
343 | FixedPrecision::initVisibleDigitsWithExponent( | |
344 | double value, | |
345 | VisibleDigitsWithExponent &digits, | |
346 | UErrorCode &status) const { | |
347 | digits.clear(); | |
348 | initVisibleDigits(value, digits.fMantissa, status); | |
349 | return digits; | |
350 | } | |
351 | ||
352 | VisibleDigitsWithExponent & | |
353 | FixedPrecision::initVisibleDigitsWithExponent( | |
354 | int64_t value, | |
355 | VisibleDigitsWithExponent &digits, | |
356 | UErrorCode &status) const { | |
357 | digits.clear(); | |
358 | initVisibleDigits(value, digits.fMantissa, status); | |
359 | return digits; | |
360 | } | |
361 | ||
362 | ScientificPrecision::ScientificPrecision() : fMinExponentDigits(1) { | |
363 | } | |
364 | ||
365 | DigitList & | |
366 | ScientificPrecision::round(DigitList &value, UErrorCode &status) const { | |
367 | if (U_FAILURE(status)) { | |
368 | return value; | |
369 | } | |
370 | int32_t exponent = value.getScientificExponent( | |
371 | fMantissa.fMin.getIntDigitCount(), getMultiplier()); | |
372 | return fMantissa.round(value, exponent, status); | |
373 | } | |
374 | ||
375 | int32_t | |
376 | ScientificPrecision::toScientific(DigitList &value) const { | |
377 | return value.toScientific( | |
378 | fMantissa.fMin.getIntDigitCount(), getMultiplier()); | |
379 | } | |
380 | ||
381 | int32_t | |
382 | ScientificPrecision::getMultiplier() const { | |
383 | int32_t maxIntDigitCount = fMantissa.fMax.getIntDigitCount(); | |
384 | if (maxIntDigitCount == INT32_MAX) { | |
385 | return 1; | |
386 | } | |
387 | int32_t multiplier = | |
388 | maxIntDigitCount - fMantissa.fMin.getIntDigitCount() + 1; | |
389 | return (multiplier < 1 ? 1 : multiplier); | |
390 | } | |
391 | ||
392 | VisibleDigitsWithExponent & | |
393 | ScientificPrecision::initVisibleDigitsWithExponent( | |
394 | DigitList &value, | |
395 | VisibleDigitsWithExponent &digits, | |
396 | UErrorCode &status) const { | |
397 | if (U_FAILURE(status)) { | |
398 | return digits; | |
399 | } | |
400 | digits.clear(); | |
401 | if (FixedPrecision::handleNonNumeric(value, digits.fMantissa)) { | |
402 | return digits; | |
403 | } | |
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; | |
411 | return digits; | |
412 | } | |
413 | ||
414 | VisibleDigitsWithExponent & | |
415 | ScientificPrecision::initVisibleDigitsWithExponent( | |
416 | double value, | |
417 | VisibleDigitsWithExponent &digits, | |
418 | UErrorCode &status) const { | |
419 | if (U_FAILURE(status)) { | |
420 | return digits; | |
421 | } | |
422 | DigitList digitList; | |
423 | digitList.set(value); | |
424 | return initVisibleDigitsWithExponent(digitList, digits, status); | |
425 | } | |
426 | ||
427 | VisibleDigitsWithExponent & | |
428 | ScientificPrecision::initVisibleDigitsWithExponent( | |
429 | int64_t value, | |
430 | VisibleDigitsWithExponent &digits, | |
431 | UErrorCode &status) const { | |
432 | if (U_FAILURE(status)) { | |
433 | return digits; | |
434 | } | |
435 | DigitList digitList; | |
436 | digitList.set(value); | |
437 | return initVisibleDigitsWithExponent(digitList, digits, status); | |
438 | } | |
439 | ||
440 | ||
441 | U_NAMESPACE_END | |
442 | #endif /* #if !UCONFIG_NO_FORMATTING */ |