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