File: | out/../deps/icu-small/source/i18n/number_decimalquantity.cpp |
Warning: | line 1197, column 27 The result of the right shift is undefined due to shifting by '64', which is greater or equal to the width of type 'uint64_t' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // © 2017 and later: Unicode, Inc. and others. | |||
2 | // License & terms of use: http://www.unicode.org/copyright.html | |||
3 | ||||
4 | #include "unicode/utypes.h" | |||
5 | ||||
6 | #if !UCONFIG_NO_FORMATTING0 | |||
7 | ||||
8 | #include <cstdlib> | |||
9 | #include <cmath> | |||
10 | #include <limits> | |||
11 | #include <stdlib.h> | |||
12 | ||||
13 | #include "unicode/plurrule.h" | |||
14 | #include "cmemory.h" | |||
15 | #include "number_decnum.h" | |||
16 | #include "putilimp.h" | |||
17 | #include "number_decimalquantity.h" | |||
18 | #include "number_roundingutils.h" | |||
19 | #include "double-conversion.h" | |||
20 | #include "charstr.h" | |||
21 | #include "number_utils.h" | |||
22 | #include "uassert.h" | |||
23 | #include "util.h" | |||
24 | ||||
25 | using namespace icu; | |||
26 | using namespace icu::number; | |||
27 | using namespace icu::number::impl; | |||
28 | ||||
29 | using icu::double_conversion::DoubleToStringConverter; | |||
30 | using icu::double_conversion::StringToDoubleConverter; | |||
31 | ||||
32 | namespace { | |||
33 | ||||
34 | int8_t NEGATIVE_FLAG = 1; | |||
35 | int8_t INFINITY_FLAG = 2; | |||
36 | int8_t NAN_FLAG = 4; | |||
37 | ||||
38 | /** Helper function for safe subtraction (no overflow). */ | |||
39 | inline int32_t safeSubtract(int32_t a, int32_t b) { | |||
40 | // Note: In C++, signed integer subtraction is undefined behavior. | |||
41 | int32_t diff = static_cast<int32_t>(static_cast<uint32_t>(a) - static_cast<uint32_t>(b)); | |||
42 | if (b < 0 && diff < a) { return INT32_MAX(2147483647); } | |||
43 | if (b > 0 && diff > a) { return INT32_MIN(-2147483647-1); } | |||
44 | return diff; | |||
45 | } | |||
46 | ||||
47 | static double DOUBLE_MULTIPLIERS[] = { | |||
48 | 1e0, | |||
49 | 1e1, | |||
50 | 1e2, | |||
51 | 1e3, | |||
52 | 1e4, | |||
53 | 1e5, | |||
54 | 1e6, | |||
55 | 1e7, | |||
56 | 1e8, | |||
57 | 1e9, | |||
58 | 1e10, | |||
59 | 1e11, | |||
60 | 1e12, | |||
61 | 1e13, | |||
62 | 1e14, | |||
63 | 1e15, | |||
64 | 1e16, | |||
65 | 1e17, | |||
66 | 1e18, | |||
67 | 1e19, | |||
68 | 1e20, | |||
69 | 1e21}; | |||
70 | ||||
71 | } // namespace | |||
72 | ||||
73 | icu::IFixedDecimal::~IFixedDecimal() = default; | |||
74 | ||||
75 | DecimalQuantity::DecimalQuantity() { | |||
76 | setBcdToZero(); | |||
77 | flags = 0; | |||
78 | } | |||
79 | ||||
80 | DecimalQuantity::~DecimalQuantity() { | |||
81 | if (usingBytes) { | |||
82 | uprv_freeuprv_free_71(fBCD.bcdBytes.ptr); | |||
83 | fBCD.bcdBytes.ptr = nullptr; | |||
84 | usingBytes = false; | |||
85 | } | |||
86 | } | |||
87 | ||||
88 | DecimalQuantity::DecimalQuantity(const DecimalQuantity &other) { | |||
89 | *this = other; | |||
90 | } | |||
91 | ||||
92 | DecimalQuantity::DecimalQuantity(DecimalQuantity&& src) U_NOEXCEPTnoexcept { | |||
93 | *this = std::move(src); | |||
94 | } | |||
95 | ||||
96 | DecimalQuantity &DecimalQuantity::operator=(const DecimalQuantity &other) { | |||
97 | if (this == &other) { | |||
98 | return *this; | |||
99 | } | |||
100 | copyBcdFrom(other); | |||
101 | copyFieldsFrom(other); | |||
102 | return *this; | |||
103 | } | |||
104 | ||||
105 | DecimalQuantity& DecimalQuantity::operator=(DecimalQuantity&& src) U_NOEXCEPTnoexcept { | |||
106 | if (this == &src) { | |||
107 | return *this; | |||
108 | } | |||
109 | moveBcdFrom(src); | |||
110 | copyFieldsFrom(src); | |||
111 | return *this; | |||
112 | } | |||
113 | ||||
114 | void DecimalQuantity::copyFieldsFrom(const DecimalQuantity& other) { | |||
115 | bogus = other.bogus; | |||
116 | lReqPos = other.lReqPos; | |||
117 | rReqPos = other.rReqPos; | |||
118 | scale = other.scale; | |||
119 | precision = other.precision; | |||
120 | flags = other.flags; | |||
121 | origDouble = other.origDouble; | |||
122 | origDelta = other.origDelta; | |||
123 | isApproximate = other.isApproximate; | |||
124 | exponent = other.exponent; | |||
125 | } | |||
126 | ||||
127 | void DecimalQuantity::clear() { | |||
128 | lReqPos = 0; | |||
129 | rReqPos = 0; | |||
130 | flags = 0; | |||
131 | setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data | |||
132 | } | |||
133 | ||||
134 | void DecimalQuantity::setMinInteger(int32_t minInt) { | |||
135 | // Validation should happen outside of DecimalQuantity, e.g., in the Precision class. | |||
136 | U_ASSERT(minInt >= 0)(void)0; | |||
137 | ||||
138 | // Special behavior: do not set minInt to be less than what is already set. | |||
139 | // This is so significant digits rounding can set the integer length. | |||
140 | if (minInt < lReqPos) { | |||
141 | minInt = lReqPos; | |||
142 | } | |||
143 | ||||
144 | // Save values into internal state | |||
145 | lReqPos = minInt; | |||
146 | } | |||
147 | ||||
148 | void DecimalQuantity::setMinFraction(int32_t minFrac) { | |||
149 | // Validation should happen outside of DecimalQuantity, e.g., in the Precision class. | |||
150 | U_ASSERT(minFrac >= 0)(void)0; | |||
151 | ||||
152 | // Save values into internal state | |||
153 | // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE | |||
154 | rReqPos = -minFrac; | |||
155 | } | |||
156 | ||||
157 | void DecimalQuantity::applyMaxInteger(int32_t maxInt) { | |||
158 | // Validation should happen outside of DecimalQuantity, e.g., in the Precision class. | |||
159 | U_ASSERT(maxInt >= 0)(void)0; | |||
160 | ||||
161 | if (precision == 0) { | |||
162 | return; | |||
163 | } | |||
164 | ||||
165 | if (maxInt <= scale) { | |||
166 | setBcdToZero(); | |||
167 | return; | |||
168 | } | |||
169 | ||||
170 | int32_t magnitude = getMagnitude(); | |||
171 | if (maxInt <= magnitude) { | |||
172 | popFromLeft(magnitude - maxInt + 1); | |||
173 | compact(); | |||
174 | } | |||
175 | } | |||
176 | ||||
177 | uint64_t DecimalQuantity::getPositionFingerprint() const { | |||
178 | uint64_t fingerprint = 0; | |||
179 | fingerprint ^= (lReqPos << 16); | |||
180 | fingerprint ^= (static_cast<uint64_t>(rReqPos) << 32); | |||
181 | return fingerprint; | |||
182 | } | |||
183 | ||||
184 | void DecimalQuantity::roundToIncrement( | |||
185 | uint64_t increment, | |||
186 | digits_t magnitude, | |||
187 | RoundingMode roundingMode, | |||
188 | UErrorCode& status) { | |||
189 | // Do not call this method with an increment having only a 1 or a 5 digit! | |||
190 | // Use a more efficient call to either roundToMagnitude() or roundToNickel(). | |||
191 | // Check a few popular rounding increments; a more thorough check is in Java. | |||
192 | U_ASSERT(increment != 1)(void)0; | |||
193 | U_ASSERT(increment != 5)(void)0; | |||
194 | ||||
195 | DecimalQuantity incrementDQ; | |||
196 | incrementDQ.setToLong(increment); | |||
197 | incrementDQ.adjustMagnitude(magnitude); | |||
198 | DecNum incrementDN; | |||
199 | incrementDQ.toDecNum(incrementDN, status); | |||
200 | if (U_FAILURE(status)) { return; } | |||
201 | ||||
202 | // Divide this DecimalQuantity by the increment, round, then multiply back. | |||
203 | divideBy(incrementDN, status); | |||
204 | if (U_FAILURE(status)) { return; } | |||
205 | roundToMagnitude(0, roundingMode, status); | |||
206 | if (U_FAILURE(status)) { return; } | |||
207 | multiplyBy(incrementDN, status); | |||
208 | if (U_FAILURE(status)) { return; } | |||
209 | } | |||
210 | ||||
211 | void DecimalQuantity::multiplyBy(const DecNum& multiplicand, UErrorCode& status) { | |||
212 | if (isZeroish()) { | |||
213 | return; | |||
214 | } | |||
215 | // Convert to DecNum, multiply, and convert back. | |||
216 | DecNum decnum; | |||
217 | toDecNum(decnum, status); | |||
218 | if (U_FAILURE(status)) { return; } | |||
219 | decnum.multiplyBy(multiplicand, status); | |||
220 | if (U_FAILURE(status)) { return; } | |||
221 | setToDecNum(decnum, status); | |||
222 | } | |||
223 | ||||
224 | void DecimalQuantity::divideBy(const DecNum& divisor, UErrorCode& status) { | |||
225 | if (isZeroish()) { | |||
226 | return; | |||
227 | } | |||
228 | // Convert to DecNum, multiply, and convert back. | |||
229 | DecNum decnum; | |||
230 | toDecNum(decnum, status); | |||
231 | if (U_FAILURE(status)) { return; } | |||
232 | decnum.divideBy(divisor, status); | |||
233 | if (U_FAILURE(status)) { return; } | |||
234 | setToDecNum(decnum, status); | |||
235 | } | |||
236 | ||||
237 | void DecimalQuantity::negate() { | |||
238 | flags ^= NEGATIVE_FLAG; | |||
239 | } | |||
240 | ||||
241 | int32_t DecimalQuantity::getMagnitude() const { | |||
242 | U_ASSERT(precision != 0)(void)0; | |||
243 | return scale + precision - 1; | |||
244 | } | |||
245 | ||||
246 | bool DecimalQuantity::adjustMagnitude(int32_t delta) { | |||
247 | if (precision != 0) { | |||
248 | // i.e., scale += delta; origDelta += delta | |||
249 | bool overflow = uprv_add32_overflowuprv_add32_overflow_71(scale, delta, &scale); | |||
250 | overflow = uprv_add32_overflowuprv_add32_overflow_71(origDelta, delta, &origDelta) || overflow; | |||
251 | // Make sure that precision + scale won't overflow, either | |||
252 | int32_t dummy; | |||
253 | overflow = overflow || uprv_add32_overflowuprv_add32_overflow_71(scale, precision, &dummy); | |||
254 | return overflow; | |||
255 | } | |||
256 | return false; | |||
257 | } | |||
258 | ||||
259 | int32_t DecimalQuantity::adjustToZeroScale() { | |||
260 | int32_t retval = scale; | |||
261 | scale = 0; | |||
262 | return retval; | |||
263 | } | |||
264 | ||||
265 | double DecimalQuantity::getPluralOperand(PluralOperand operand) const { | |||
266 | // If this assertion fails, you need to call roundToInfinity() or some other rounding method. | |||
267 | // See the comment at the top of this file explaining the "isApproximate" field. | |||
268 | U_ASSERT(!isApproximate)(void)0; | |||
269 | ||||
270 | switch (operand) { | |||
271 | case PLURAL_OPERAND_I: | |||
272 | // Invert the negative sign if necessary | |||
273 | return static_cast<double>(isNegative() ? -toLong(true) : toLong(true)); | |||
274 | case PLURAL_OPERAND_F: | |||
275 | return static_cast<double>(toFractionLong(true)); | |||
276 | case PLURAL_OPERAND_T: | |||
277 | return static_cast<double>(toFractionLong(false)); | |||
278 | case PLURAL_OPERAND_V: | |||
279 | return fractionCount(); | |||
280 | case PLURAL_OPERAND_W: | |||
281 | return fractionCountWithoutTrailingZeros(); | |||
282 | case PLURAL_OPERAND_E: | |||
283 | return static_cast<double>(getExponent()); | |||
284 | case PLURAL_OPERAND_C: | |||
285 | // Plural operand `c` is currently an alias for `e`. | |||
286 | return static_cast<double>(getExponent()); | |||
287 | default: | |||
288 | return std::abs(toDouble()); | |||
289 | } | |||
290 | } | |||
291 | ||||
292 | int32_t DecimalQuantity::getExponent() const { | |||
293 | return exponent; | |||
294 | } | |||
295 | ||||
296 | void DecimalQuantity::adjustExponent(int delta) { | |||
297 | exponent = exponent + delta; | |||
298 | } | |||
299 | ||||
300 | void DecimalQuantity::resetExponent() { | |||
301 | adjustMagnitude(exponent); | |||
302 | exponent = 0; | |||
303 | } | |||
304 | ||||
305 | bool DecimalQuantity::hasIntegerValue() const { | |||
306 | return scale >= 0; | |||
307 | } | |||
308 | ||||
309 | int32_t DecimalQuantity::getUpperDisplayMagnitude() const { | |||
310 | // If this assertion fails, you need to call roundToInfinity() or some other rounding method. | |||
311 | // See the comment in the header file explaining the "isApproximate" field. | |||
312 | U_ASSERT(!isApproximate)(void)0; | |||
313 | ||||
314 | int32_t magnitude = scale + precision; | |||
315 | int32_t result = (lReqPos > magnitude) ? lReqPos : magnitude; | |||
316 | return result - 1; | |||
317 | } | |||
318 | ||||
319 | int32_t DecimalQuantity::getLowerDisplayMagnitude() const { | |||
320 | // If this assertion fails, you need to call roundToInfinity() or some other rounding method. | |||
321 | // See the comment in the header file explaining the "isApproximate" field. | |||
322 | U_ASSERT(!isApproximate)(void)0; | |||
323 | ||||
324 | int32_t magnitude = scale; | |||
325 | int32_t result = (rReqPos < magnitude) ? rReqPos : magnitude; | |||
326 | return result; | |||
327 | } | |||
328 | ||||
329 | int8_t DecimalQuantity::getDigit(int32_t magnitude) const { | |||
330 | // If this assertion fails, you need to call roundToInfinity() or some other rounding method. | |||
331 | // See the comment at the top of this file explaining the "isApproximate" field. | |||
332 | U_ASSERT(!isApproximate)(void)0; | |||
333 | ||||
334 | return getDigitPos(magnitude - scale); | |||
335 | } | |||
336 | ||||
337 | int32_t DecimalQuantity::fractionCount() const { | |||
338 | int32_t fractionCountWithExponent = -getLowerDisplayMagnitude() - exponent; | |||
339 | return fractionCountWithExponent > 0 ? fractionCountWithExponent : 0; | |||
340 | } | |||
341 | ||||
342 | int32_t DecimalQuantity::fractionCountWithoutTrailingZeros() const { | |||
343 | int32_t fractionCountWithExponent = -scale - exponent; | |||
344 | return fractionCountWithExponent > 0 ? fractionCountWithExponent : 0; // max(-fractionCountWithExponent, 0) | |||
345 | } | |||
346 | ||||
347 | bool DecimalQuantity::isNegative() const { | |||
348 | return (flags & NEGATIVE_FLAG) != 0; | |||
349 | } | |||
350 | ||||
351 | Signum DecimalQuantity::signum() const { | |||
352 | bool isZero = (isZeroish() && !isInfinite()); | |||
353 | bool isNeg = isNegative(); | |||
354 | if (isZero && isNeg) { | |||
355 | return SIGNUM_NEG_ZERO; | |||
356 | } else if (isZero) { | |||
357 | return SIGNUM_POS_ZERO; | |||
358 | } else if (isNeg) { | |||
359 | return SIGNUM_NEG; | |||
360 | } else { | |||
361 | return SIGNUM_POS; | |||
362 | } | |||
363 | } | |||
364 | ||||
365 | bool DecimalQuantity::isInfinite() const { | |||
366 | return (flags & INFINITY_FLAG) != 0; | |||
367 | } | |||
368 | ||||
369 | bool DecimalQuantity::isNaN() const { | |||
370 | return (flags & NAN_FLAG) != 0; | |||
371 | } | |||
372 | ||||
373 | bool DecimalQuantity::isZeroish() const { | |||
374 | return precision == 0; | |||
375 | } | |||
376 | ||||
377 | DecimalQuantity &DecimalQuantity::setToInt(int32_t n) { | |||
378 | setBcdToZero(); | |||
379 | flags = 0; | |||
380 | if (n == INT32_MIN(-2147483647-1)) { | |||
381 | flags |= NEGATIVE_FLAG; | |||
382 | // leave as INT32_MIN; handled below in _setToInt() | |||
383 | } else if (n < 0) { | |||
384 | flags |= NEGATIVE_FLAG; | |||
385 | n = -n; | |||
386 | } | |||
387 | if (n != 0) { | |||
388 | _setToInt(n); | |||
389 | compact(); | |||
390 | } | |||
391 | return *this; | |||
392 | } | |||
393 | ||||
394 | void DecimalQuantity::_setToInt(int32_t n) { | |||
395 | if (n == INT32_MIN(-2147483647-1)) { | |||
396 | readLongToBcd(-static_cast<int64_t>(n)); | |||
397 | } else { | |||
398 | readIntToBcd(n); | |||
399 | } | |||
400 | } | |||
401 | ||||
402 | DecimalQuantity &DecimalQuantity::setToLong(int64_t n) { | |||
403 | setBcdToZero(); | |||
404 | flags = 0; | |||
405 | if (n < 0 && n > INT64_MIN(-9223372036854775807L -1)) { | |||
406 | flags |= NEGATIVE_FLAG; | |||
407 | n = -n; | |||
408 | } | |||
409 | if (n != 0) { | |||
410 | _setToLong(n); | |||
411 | compact(); | |||
412 | } | |||
413 | return *this; | |||
414 | } | |||
415 | ||||
416 | void DecimalQuantity::_setToLong(int64_t n) { | |||
417 | if (n == INT64_MIN(-9223372036854775807L -1)) { | |||
418 | DecNum decnum; | |||
419 | UErrorCode localStatus = U_ZERO_ERROR; | |||
420 | decnum.setTo("9.223372036854775808E+18", localStatus); | |||
421 | if (U_FAILURE(localStatus)) { return; } // unexpected | |||
422 | flags |= NEGATIVE_FLAG; | |||
423 | readDecNumberToBcd(decnum); | |||
424 | } else if (n <= INT32_MAX(2147483647)) { | |||
425 | readIntToBcd(static_cast<int32_t>(n)); | |||
426 | } else { | |||
427 | readLongToBcd(n); | |||
428 | } | |||
429 | } | |||
430 | ||||
431 | DecimalQuantity &DecimalQuantity::setToDouble(double n) { | |||
432 | setBcdToZero(); | |||
433 | flags = 0; | |||
434 | // signbit() from <math.h> handles +0.0 vs -0.0 | |||
435 | if (std::signbit(n)) { | |||
| ||||
436 | flags |= NEGATIVE_FLAG; | |||
437 | n = -n; | |||
438 | } | |||
439 | if (std::isnan(n) != 0) { | |||
440 | flags |= NAN_FLAG; | |||
441 | } else if (std::isfinite(n) == 0) { | |||
442 | flags |= INFINITY_FLAG; | |||
443 | } else if (n != 0) { | |||
444 | _setToDoubleFast(n); | |||
445 | compact(); | |||
446 | } | |||
447 | return *this; | |||
448 | } | |||
449 | ||||
450 | void DecimalQuantity::_setToDoubleFast(double n) { | |||
451 | isApproximate = true; | |||
452 | origDouble = n; | |||
453 | origDelta = 0; | |||
454 | ||||
455 | // Make sure the double is an IEEE 754 double. If not, fall back to the slow path right now. | |||
456 | // TODO: Make a fast path for other types of doubles. | |||
457 | if (!std::numeric_limits<double>::is_iec559
| |||
458 | convertToAccurateDouble(); | |||
459 | return; | |||
460 | } | |||
461 | ||||
462 | // To get the bits from the double, use memcpy, which takes care of endianness. | |||
463 | uint64_t ieeeBits; | |||
464 | uprv_memcpy(&ieeeBits, &n, sizeof(n))do { clang diagnostic push
clang diagnostic ignored "-Waddress" (void)0; (void)0; clang diagnostic pop :: memcpy(&ieeeBits , &n, sizeof(n)); } while (false); | |||
465 | int32_t exponent = static_cast<int32_t>((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff; | |||
466 | ||||
467 | // Not all integers can be represented exactly for exponent > 52 | |||
468 | if (exponent <= 52 && static_cast<int64_t>(n) == n) { | |||
469 | _setToLong(static_cast<int64_t>(n)); | |||
470 | return; | |||
471 | } | |||
472 | ||||
473 | if (exponent == -1023 || exponent == 1024) { | |||
474 | // The extreme values of exponent are special; use slow path. | |||
475 | convertToAccurateDouble(); | |||
476 | return; | |||
477 | } | |||
478 | ||||
479 | // 3.3219... is log2(10) | |||
480 | auto fracLength = static_cast<int32_t> ((52 - exponent) / 3.32192809488736234787031942948939017586); | |||
481 | if (fracLength >= 0) { | |||
482 | int32_t i = fracLength; | |||
483 | // 1e22 is the largest exact double. | |||
484 | for (; i >= 22; i -= 22) n *= 1e22; | |||
485 | n *= DOUBLE_MULTIPLIERS[i]; | |||
486 | } else { | |||
487 | int32_t i = fracLength; | |||
488 | // 1e22 is the largest exact double. | |||
489 | for (; i <= -22; i += 22) n /= 1e22; | |||
490 | n /= DOUBLE_MULTIPLIERS[-i]; | |||
491 | } | |||
492 | auto result = static_cast<int64_t>(uprv_rounduprv_round_71(n)); | |||
493 | if (result != 0) { | |||
494 | _setToLong(result); | |||
495 | scale -= fracLength; | |||
496 | } | |||
497 | } | |||
498 | ||||
499 | void DecimalQuantity::convertToAccurateDouble() { | |||
500 | U_ASSERT(origDouble != 0)(void)0; | |||
501 | int32_t delta = origDelta; | |||
502 | ||||
503 | // Call the slow oracle function (Double.toString in Java, DoubleToAscii in C++). | |||
504 | char buffer[DoubleToStringConverter::kBase10MaximalLength + 1]; | |||
505 | bool sign; // unused; always positive | |||
506 | int32_t length; | |||
507 | int32_t point; | |||
508 | DoubleToStringConverter::DoubleToAscii( | |||
509 | origDouble, | |||
510 | DoubleToStringConverter::DtoaMode::SHORTEST, | |||
511 | 0, | |||
512 | buffer, | |||
513 | sizeof(buffer), | |||
514 | &sign, | |||
515 | &length, | |||
516 | &point | |||
517 | ); | |||
518 | ||||
519 | setBcdToZero(); | |||
520 | readDoubleConversionToBcd(buffer, length, point); | |||
521 | scale += delta; | |||
522 | explicitExactDouble = true; | |||
523 | } | |||
524 | ||||
525 | DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n, UErrorCode& status) { | |||
526 | setBcdToZero(); | |||
527 | flags = 0; | |||
528 | ||||
529 | // Compute the decNumber representation | |||
530 | DecNum decnum; | |||
531 | decnum.setTo(n, status); | |||
532 | ||||
533 | _setToDecNum(decnum, status); | |||
534 | return *this; | |||
535 | } | |||
536 | ||||
537 | DecimalQuantity& DecimalQuantity::setToDecNum(const DecNum& decnum, UErrorCode& status) { | |||
538 | setBcdToZero(); | |||
539 | flags = 0; | |||
540 | ||||
541 | _setToDecNum(decnum, status); | |||
542 | return *this; | |||
543 | } | |||
544 | ||||
545 | void DecimalQuantity::_setToDecNum(const DecNum& decnum, UErrorCode& status) { | |||
546 | if (U_FAILURE(status)) { return; } | |||
547 | if (decnum.isNegative()) { | |||
548 | flags |= NEGATIVE_FLAG; | |||
549 | } | |||
550 | if (decnum.isNaN()) { | |||
551 | flags |= NAN_FLAG; | |||
552 | } else if (decnum.isInfinity()) { | |||
553 | flags |= INFINITY_FLAG; | |||
554 | } else if (!decnum.isZero()) { | |||
555 | readDecNumberToBcd(decnum); | |||
556 | compact(); | |||
557 | } | |||
558 | } | |||
559 | ||||
560 | DecimalQuantity DecimalQuantity::fromExponentString(UnicodeString num, UErrorCode& status) { | |||
561 | if (num.indexOf(u'e') >= 0 || num.indexOf(u'c') >= 0 | |||
562 | || num.indexOf(u'E') >= 0 || num.indexOf(u'C') >= 0) { | |||
563 | int32_t ePos = num.lastIndexOf('e'); | |||
564 | if (ePos < 0) { | |||
565 | ePos = num.lastIndexOf('c'); | |||
566 | } | |||
567 | if (ePos < 0) { | |||
568 | ePos = num.lastIndexOf('E'); | |||
569 | } | |||
570 | if (ePos < 0) { | |||
571 | ePos = num.lastIndexOf('C'); | |||
572 | } | |||
573 | int32_t expNumPos = ePos + 1; | |||
574 | UnicodeString exponentStr = num.tempSubString(expNumPos, num.length() - expNumPos); | |||
575 | ||||
576 | // parse exponentStr into exponent, but note that parseAsciiInteger doesn't handle the minus sign | |||
577 | bool isExpStrNeg = num[expNumPos] == u'-'; | |||
578 | int32_t exponentParsePos = isExpStrNeg ? 1 : 0; | |||
579 | int32_t exponent = ICU_Utility::parseAsciiInteger(exponentStr, exponentParsePos); | |||
580 | exponent = isExpStrNeg ? -exponent : exponent; | |||
581 | ||||
582 | // Compute the decNumber representation | |||
583 | UnicodeString fractionStr = num.tempSubString(0, ePos); | |||
584 | CharString fracCharStr = CharString(); | |||
585 | fracCharStr.appendInvariantChars(fractionStr, status); | |||
586 | DecNum decnum; | |||
587 | decnum.setTo(fracCharStr.toStringPiece(), status); | |||
588 | ||||
589 | // Clear and set this DecimalQuantity instance | |||
590 | DecimalQuantity dq; | |||
591 | dq.setToDecNum(decnum, status); | |||
592 | int32_t numFracDigit = getVisibleFractionCount(fractionStr); | |||
593 | dq.setMinFraction(numFracDigit); | |||
594 | dq.adjustExponent(exponent); | |||
595 | ||||
596 | return dq; | |||
597 | } else { | |||
598 | DecimalQuantity dq; | |||
599 | int numFracDigit = getVisibleFractionCount(num); | |||
600 | ||||
601 | CharString numCharStr = CharString(); | |||
602 | numCharStr.appendInvariantChars(num, status); | |||
603 | dq.setToDecNumber(numCharStr.toStringPiece(), status); | |||
604 | ||||
605 | dq.setMinFraction(numFracDigit); | |||
606 | return dq; | |||
607 | } | |||
608 | } | |||
609 | ||||
610 | int32_t DecimalQuantity::getVisibleFractionCount(UnicodeString value) { | |||
611 | int decimalPos = value.indexOf('.') + 1; | |||
612 | if (decimalPos == 0) { | |||
613 | return 0; | |||
614 | } else { | |||
615 | return value.length() - decimalPos; | |||
616 | } | |||
617 | } | |||
618 | ||||
619 | int64_t DecimalQuantity::toLong(bool truncateIfOverflow) const { | |||
620 | // NOTE: Call sites should be guarded by fitsInLong(), like this: | |||
621 | // if (dq.fitsInLong()) { /* use dq.toLong() */ } else { /* use some fallback */ } | |||
622 | // Fallback behavior upon truncateIfOverflow is to truncate at 17 digits. | |||
623 | uint64_t result = 0L; | |||
624 | int32_t upperMagnitude = exponent + scale + precision - 1; | |||
625 | if (truncateIfOverflow) { | |||
626 | upperMagnitude = std::min(upperMagnitude, 17); | |||
627 | } | |||
628 | for (int32_t magnitude = upperMagnitude; magnitude >= 0; magnitude--) { | |||
629 | result = result * 10 + getDigitPos(magnitude - scale - exponent); | |||
630 | } | |||
631 | if (isNegative()) { | |||
632 | return static_cast<int64_t>(0LL - result); // i.e., -result | |||
633 | } | |||
634 | return static_cast<int64_t>(result); | |||
635 | } | |||
636 | ||||
637 | uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const { | |||
638 | uint64_t result = 0L; | |||
639 | int32_t magnitude = -1 - exponent; | |||
640 | int32_t lowerMagnitude = scale; | |||
641 | if (includeTrailingZeros) { | |||
642 | lowerMagnitude = std::min(lowerMagnitude, rReqPos); | |||
643 | } | |||
644 | for (; magnitude >= lowerMagnitude && result <= 1e18L; magnitude--) { | |||
645 | result = result * 10 + getDigitPos(magnitude - scale); | |||
646 | } | |||
647 | // Remove trailing zeros; this can happen during integer overflow cases. | |||
648 | if (!includeTrailingZeros) { | |||
649 | while (result > 0 && (result % 10) == 0) { | |||
650 | result /= 10; | |||
651 | } | |||
652 | } | |||
653 | return result; | |||
654 | } | |||
655 | ||||
656 | bool DecimalQuantity::fitsInLong(bool ignoreFraction) const { | |||
657 | if (isInfinite() || isNaN()) { | |||
658 | return false; | |||
659 | } | |||
660 | if (isZeroish()) { | |||
661 | return true; | |||
662 | } | |||
663 | if (exponent + scale < 0 && !ignoreFraction) { | |||
664 | return false; | |||
665 | } | |||
666 | int magnitude = getMagnitude(); | |||
667 | if (magnitude < 18) { | |||
668 | return true; | |||
669 | } | |||
670 | if (magnitude > 18) { | |||
671 | return false; | |||
672 | } | |||
673 | // Hard case: the magnitude is 10^18. | |||
674 | // The largest int64 is: 9,223,372,036,854,775,807 | |||
675 | for (int p = 0; p < precision; p++) { | |||
676 | int8_t digit = getDigit(18 - p); | |||
677 | static int8_t INT64_BCD[] = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 }; | |||
678 | if (digit < INT64_BCD[p]) { | |||
679 | return true; | |||
680 | } else if (digit > INT64_BCD[p]) { | |||
681 | return false; | |||
682 | } | |||
683 | } | |||
684 | // Exactly equal to max long plus one. | |||
685 | return isNegative(); | |||
686 | } | |||
687 | ||||
688 | double DecimalQuantity::toDouble() const { | |||
689 | // If this assertion fails, you need to call roundToInfinity() or some other rounding method. | |||
690 | // See the comment in the header file explaining the "isApproximate" field. | |||
691 | U_ASSERT(!isApproximate)(void)0; | |||
692 | ||||
693 | if (isNaN()) { | |||
694 | return NAN(__builtin_nanf ("")); | |||
695 | } else if (isInfinite()) { | |||
696 | return isNegative() ? -INFINITY(__builtin_inff ()) : INFINITY(__builtin_inff ()); | |||
697 | } | |||
698 | ||||
699 | // We are processing well-formed input, so we don't need any special options to StringToDoubleConverter. | |||
700 | StringToDoubleConverter converter(0, 0, 0, "", ""); | |||
701 | UnicodeString numberString = this->toScientificString(); | |||
702 | int32_t count; | |||
703 | return converter.StringToDouble( | |||
704 | reinterpret_cast<const uint16_t*>(numberString.getBuffer()), | |||
705 | numberString.length(), | |||
706 | &count); | |||
707 | } | |||
708 | ||||
709 | DecNum& DecimalQuantity::toDecNum(DecNum& output, UErrorCode& status) const { | |||
710 | // Special handling for zero | |||
711 | if (precision == 0) { | |||
712 | output.setTo("0", status); | |||
713 | return output; | |||
714 | } | |||
715 | ||||
716 | // Use the BCD constructor. We need to do a little bit of work to convert, though. | |||
717 | // The decNumber constructor expects most-significant first, but we store least-significant first. | |||
718 | MaybeStackArray<uint8_t, 20> ubcd(precision, status); | |||
719 | if (U_FAILURE(status)) { | |||
720 | return output; | |||
721 | } | |||
722 | for (int32_t m = 0; m < precision; m++) { | |||
723 | ubcd[precision - m - 1] = static_cast<uint8_t>(getDigitPos(m)); | |||
724 | } | |||
725 | output.setTo(ubcd.getAlias(), precision, scale, isNegative(), status); | |||
726 | return output; | |||
727 | } | |||
728 | ||||
729 | void DecimalQuantity::truncate() { | |||
730 | if (scale < 0) { | |||
731 | shiftRight(-scale); | |||
732 | scale = 0; | |||
733 | compact(); | |||
734 | } | |||
735 | } | |||
736 | ||||
737 | void DecimalQuantity::roundToNickel(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) { | |||
738 | roundToMagnitude(magnitude, roundingMode, true, status); | |||
739 | } | |||
740 | ||||
741 | void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) { | |||
742 | roundToMagnitude(magnitude, roundingMode, false, status); | |||
743 | } | |||
744 | ||||
745 | void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, bool nickel, UErrorCode& status) { | |||
746 | // The position in the BCD at which rounding will be performed; digits to the right of position | |||
747 | // will be rounded away. | |||
748 | int position = safeSubtract(magnitude, scale); | |||
749 | ||||
750 | // "trailing" = least significant digit to the left of rounding | |||
751 | int8_t trailingDigit = getDigitPos(position); | |||
752 | ||||
753 | if (position <= 0 && !isApproximate && (!nickel || trailingDigit == 0 || trailingDigit == 5)) { | |||
754 | // All digits are to the left of the rounding magnitude. | |||
755 | } else if (precision == 0) { | |||
756 | // No rounding for zero. | |||
757 | } else { | |||
758 | // Perform rounding logic. | |||
759 | // "leading" = most significant digit to the right of rounding | |||
760 | int8_t leadingDigit = getDigitPos(safeSubtract(position, 1)); | |||
761 | ||||
762 | // Compute which section of the number we are in. | |||
763 | // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles) | |||
764 | // LOWER means we are between the bottom edge and the midpoint, like 1.391 | |||
765 | // MIDPOINT means we are exactly in the middle, like 1.500 | |||
766 | // UPPER means we are between the midpoint and the top edge, like 1.916 | |||
767 | roundingutils::Section section; | |||
768 | if (!isApproximate) { | |||
769 | if (nickel && trailingDigit != 2 && trailingDigit != 7) { | |||
770 | // Nickel rounding, and not at .02x or .07x | |||
771 | if (trailingDigit < 2) { | |||
772 | // .00, .01 => down to .00 | |||
773 | section = roundingutils::SECTION_LOWER; | |||
774 | } else if (trailingDigit < 5) { | |||
775 | // .03, .04 => up to .05 | |||
776 | section = roundingutils::SECTION_UPPER; | |||
777 | } else if (trailingDigit < 7) { | |||
778 | // .05, .06 => down to .05 | |||
779 | section = roundingutils::SECTION_LOWER; | |||
780 | } else { | |||
781 | // .08, .09 => up to .10 | |||
782 | section = roundingutils::SECTION_UPPER; | |||
783 | } | |||
784 | } else if (leadingDigit < 5) { | |||
785 | // Includes nickel rounding .020-.024 and .070-.074 | |||
786 | section = roundingutils::SECTION_LOWER; | |||
787 | } else if (leadingDigit > 5) { | |||
788 | // Includes nickel rounding .026-.029 and .076-.079 | |||
789 | section = roundingutils::SECTION_UPPER; | |||
790 | } else { | |||
791 | // Includes nickel rounding .025 and .075 | |||
792 | section = roundingutils::SECTION_MIDPOINT; | |||
793 | for (int p = safeSubtract(position, 2); p >= 0; p--) { | |||
794 | if (getDigitPos(p) != 0) { | |||
795 | section = roundingutils::SECTION_UPPER; | |||
796 | break; | |||
797 | } | |||
798 | } | |||
799 | } | |||
800 | } else { | |||
801 | int32_t p = safeSubtract(position, 2); | |||
802 | int32_t minP = uprv_maxuprv_max_71(0, precision - 14); | |||
803 | if (leadingDigit == 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) { | |||
804 | section = roundingutils::SECTION_LOWER_EDGE; | |||
805 | for (; p >= minP; p--) { | |||
806 | if (getDigitPos(p) != 0) { | |||
807 | section = roundingutils::SECTION_LOWER; | |||
808 | break; | |||
809 | } | |||
810 | } | |||
811 | } else if (leadingDigit == 4 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) { | |||
812 | section = roundingutils::SECTION_MIDPOINT; | |||
813 | for (; p >= minP; p--) { | |||
814 | if (getDigitPos(p) != 9) { | |||
815 | section = roundingutils::SECTION_LOWER; | |||
816 | break; | |||
817 | } | |||
818 | } | |||
819 | } else if (leadingDigit == 5 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) { | |||
820 | section = roundingutils::SECTION_MIDPOINT; | |||
821 | for (; p >= minP; p--) { | |||
822 | if (getDigitPos(p) != 0) { | |||
823 | section = roundingutils::SECTION_UPPER; | |||
824 | break; | |||
825 | } | |||
826 | } | |||
827 | } else if (leadingDigit == 9 && (!nickel || trailingDigit == 4 || trailingDigit == 9)) { | |||
828 | section = roundingutils::SECTION_UPPER_EDGE; | |||
829 | for (; p >= minP; p--) { | |||
830 | if (getDigitPos(p) != 9) { | |||
831 | section = roundingutils::SECTION_UPPER; | |||
832 | break; | |||
833 | } | |||
834 | } | |||
835 | } else if (nickel && trailingDigit != 2 && trailingDigit != 7) { | |||
836 | // Nickel rounding, and not at .02x or .07x | |||
837 | if (trailingDigit < 2) { | |||
838 | // .00, .01 => down to .00 | |||
839 | section = roundingutils::SECTION_LOWER; | |||
840 | } else if (trailingDigit < 5) { | |||
841 | // .03, .04 => up to .05 | |||
842 | section = roundingutils::SECTION_UPPER; | |||
843 | } else if (trailingDigit < 7) { | |||
844 | // .05, .06 => down to .05 | |||
845 | section = roundingutils::SECTION_LOWER; | |||
846 | } else { | |||
847 | // .08, .09 => up to .10 | |||
848 | section = roundingutils::SECTION_UPPER; | |||
849 | } | |||
850 | } else if (leadingDigit < 5) { | |||
851 | // Includes nickel rounding .020-.024 and .070-.074 | |||
852 | section = roundingutils::SECTION_LOWER; | |||
853 | } else { | |||
854 | // Includes nickel rounding .026-.029 and .076-.079 | |||
855 | section = roundingutils::SECTION_UPPER; | |||
856 | } | |||
857 | ||||
858 | bool roundsAtMidpoint = roundingutils::roundsAtMidpoint(roundingMode); | |||
859 | if (safeSubtract(position, 1) < precision - 14 || | |||
860 | (roundsAtMidpoint && section == roundingutils::SECTION_MIDPOINT) || | |||
861 | (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) { | |||
862 | // Oops! This means that we have to get the exact representation of the double, | |||
863 | // because the zone of uncertainty is along the rounding boundary. | |||
864 | convertToAccurateDouble(); | |||
865 | roundToMagnitude(magnitude, roundingMode, nickel, status); // start over | |||
866 | return; | |||
867 | } | |||
868 | ||||
869 | // Turn off the approximate double flag, since the value is now confirmed to be exact. | |||
870 | isApproximate = false; | |||
871 | origDouble = 0.0; | |||
872 | origDelta = 0; | |||
873 | ||||
874 | if (position <= 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) { | |||
875 | // All digits are to the left of the rounding magnitude. | |||
876 | return; | |||
877 | } | |||
878 | ||||
879 | // Good to continue rounding. | |||
880 | if (section == -1) { section = roundingutils::SECTION_LOWER; } | |||
881 | if (section == -2) { section = roundingutils::SECTION_UPPER; } | |||
882 | } | |||
883 | ||||
884 | // Nickel rounding "half even" goes to the nearest whole (away from the 5). | |||
885 | bool isEven = nickel | |||
886 | ? (trailingDigit < 2 || trailingDigit > 7 | |||
887 | || (trailingDigit == 2 && section != roundingutils::SECTION_UPPER) | |||
888 | || (trailingDigit == 7 && section == roundingutils::SECTION_UPPER)) | |||
889 | : (trailingDigit % 2) == 0; | |||
890 | ||||
891 | bool roundDown = roundingutils::getRoundingDirection(isEven, | |||
892 | isNegative(), | |||
893 | section, | |||
894 | roundingMode, | |||
895 | status); | |||
896 | if (U_FAILURE(status)) { | |||
897 | return; | |||
898 | } | |||
899 | ||||
900 | // Perform truncation | |||
901 | if (position >= precision) { | |||
902 | U_ASSERT(trailingDigit == 0)(void)0; | |||
903 | setBcdToZero(); | |||
904 | scale = magnitude; | |||
905 | } else { | |||
906 | shiftRight(position); | |||
907 | } | |||
908 | ||||
909 | if (nickel) { | |||
910 | if (trailingDigit < 5 && roundDown) { | |||
911 | setDigitPos(0, 0); | |||
912 | compact(); | |||
913 | return; | |||
914 | } else if (trailingDigit >= 5 && !roundDown) { | |||
915 | setDigitPos(0, 9); | |||
916 | trailingDigit = 9; | |||
917 | // do not return: use the bubbling logic below | |||
918 | } else { | |||
919 | setDigitPos(0, 5); | |||
920 | // If the quantity was set to 0, we may need to restore a digit. | |||
921 | if (precision == 0) { | |||
922 | precision = 1; | |||
923 | } | |||
924 | // compact not necessary: digit at position 0 is nonzero | |||
925 | return; | |||
926 | } | |||
927 | } | |||
928 | ||||
929 | // Bubble the result to the higher digits | |||
930 | if (!roundDown) { | |||
931 | if (trailingDigit == 9) { | |||
932 | int bubblePos = 0; | |||
933 | // Note: in the long implementation, the most digits BCD can have at this point is | |||
934 | // 15, so bubblePos <= 15 and getDigitPos(bubblePos) is safe. | |||
935 | for (; getDigitPos(bubblePos) == 9; bubblePos++) {} | |||
936 | shiftRight(bubblePos); // shift off the trailing 9s | |||
937 | } | |||
938 | int8_t digit0 = getDigitPos(0); | |||
939 | U_ASSERT(digit0 != 9)(void)0; | |||
940 | setDigitPos(0, static_cast<int8_t>(digit0 + 1)); | |||
941 | precision += 1; // in case an extra digit got added | |||
942 | } | |||
943 | ||||
944 | compact(); | |||
945 | } | |||
946 | } | |||
947 | ||||
948 | void DecimalQuantity::roundToInfinity() { | |||
949 | if (isApproximate) { | |||
950 | convertToAccurateDouble(); | |||
951 | } | |||
952 | } | |||
953 | ||||
954 | void DecimalQuantity::appendDigit(int8_t value, int32_t leadingZeros, bool appendAsInteger) { | |||
955 | U_ASSERT(leadingZeros >= 0)(void)0; | |||
956 | ||||
957 | // Zero requires special handling to maintain the invariant that the least-significant digit | |||
958 | // in the BCD is nonzero. | |||
959 | if (value == 0) { | |||
960 | if (appendAsInteger && precision != 0) { | |||
961 | scale += leadingZeros + 1; | |||
962 | } | |||
963 | return; | |||
964 | } | |||
965 | ||||
966 | // Deal with trailing zeros | |||
967 | if (scale > 0) { | |||
968 | leadingZeros += scale; | |||
969 | if (appendAsInteger) { | |||
970 | scale = 0; | |||
971 | } | |||
972 | } | |||
973 | ||||
974 | // Append digit | |||
975 | shiftLeft(leadingZeros + 1); | |||
976 | setDigitPos(0, value); | |||
977 | ||||
978 | // Fix scale if in integer mode | |||
979 | if (appendAsInteger) { | |||
980 | scale += leadingZeros + 1; | |||
981 | } | |||
982 | } | |||
983 | ||||
984 | UnicodeString DecimalQuantity::toPlainString() const { | |||
985 | U_ASSERT(!isApproximate)(void)0; | |||
986 | UnicodeString sb; | |||
987 | if (isNegative()) { | |||
988 | sb.append(u'-'); | |||
989 | } | |||
990 | if (precision == 0) { | |||
991 | sb.append(u'0'); | |||
992 | return sb; | |||
993 | } | |||
994 | int32_t upper = scale + precision + exponent - 1; | |||
995 | int32_t lower = scale + exponent; | |||
996 | if (upper < lReqPos - 1) { | |||
997 | upper = lReqPos - 1; | |||
998 | } | |||
999 | if (lower > rReqPos) { | |||
1000 | lower = rReqPos; | |||
1001 | } | |||
1002 | int32_t p = upper; | |||
1003 | if (p < 0) { | |||
1004 | sb.append(u'0'); | |||
1005 | } | |||
1006 | for (; p >= 0; p--) { | |||
1007 | sb.append(u'0' + getDigitPos(p - scale - exponent)); | |||
1008 | } | |||
1009 | if (lower < 0) { | |||
1010 | sb.append(u'.'); | |||
1011 | } | |||
1012 | for(; p >= lower; p--) { | |||
1013 | sb.append(u'0' + getDigitPos(p - scale - exponent)); | |||
1014 | } | |||
1015 | return sb; | |||
1016 | } | |||
1017 | ||||
1018 | ||||
1019 | UnicodeString DecimalQuantity::toExponentString() const { | |||
1020 | U_ASSERT(!isApproximate)(void)0; | |||
1021 | UnicodeString sb; | |||
1022 | if (isNegative()) { | |||
1023 | sb.append(u'-'); | |||
1024 | } | |||
1025 | ||||
1026 | int32_t upper = scale + precision - 1; | |||
1027 | int32_t lower = scale; | |||
1028 | if (upper < lReqPos - 1) { | |||
1029 | upper = lReqPos - 1; | |||
1030 | } | |||
1031 | if (lower > rReqPos) { | |||
1032 | lower = rReqPos; | |||
1033 | } | |||
1034 | int32_t p = upper; | |||
1035 | if (p < 0) { | |||
1036 | sb.append(u'0'); | |||
1037 | } | |||
1038 | for (; p >= 0; p--) { | |||
1039 | sb.append(u'0' + getDigitPos(p - scale)); | |||
1040 | } | |||
1041 | if (lower < 0) { | |||
1042 | sb.append(u'.'); | |||
1043 | } | |||
1044 | for(; p >= lower; p--) { | |||
1045 | sb.append(u'0' + getDigitPos(p - scale)); | |||
1046 | } | |||
1047 | ||||
1048 | if (exponent != 0) { | |||
1049 | sb.append(u'c'); | |||
1050 | ICU_Utility::appendNumber(sb, exponent); | |||
1051 | } | |||
1052 | ||||
1053 | return sb; | |||
1054 | } | |||
1055 | ||||
1056 | UnicodeString DecimalQuantity::toScientificString() const { | |||
1057 | U_ASSERT(!isApproximate)(void)0; | |||
1058 | UnicodeString result; | |||
1059 | if (isNegative()) { | |||
1060 | result.append(u'-'); | |||
1061 | } | |||
1062 | if (precision == 0) { | |||
1063 | result.append(u"0E+0", -1); | |||
1064 | return result; | |||
1065 | } | |||
1066 | int32_t upperPos = precision - 1; | |||
1067 | int32_t lowerPos = 0; | |||
1068 | int32_t p = upperPos; | |||
1069 | result.append(u'0' + getDigitPos(p)); | |||
1070 | if ((--p) >= lowerPos) { | |||
1071 | result.append(u'.'); | |||
1072 | for (; p >= lowerPos; p--) { | |||
1073 | result.append(u'0' + getDigitPos(p)); | |||
1074 | } | |||
1075 | } | |||
1076 | result.append(u'E'); | |||
1077 | int32_t _scale = upperPos + scale + exponent; | |||
1078 | if (_scale == INT32_MIN(-2147483647-1)) { | |||
1079 | result.append({u"-2147483648", -1}); | |||
1080 | return result; | |||
1081 | } else if (_scale < 0) { | |||
1082 | _scale *= -1; | |||
1083 | result.append(u'-'); | |||
1084 | } else { | |||
1085 | result.append(u'+'); | |||
1086 | } | |||
1087 | if (_scale == 0) { | |||
1088 | result.append(u'0'); | |||
1089 | } | |||
1090 | int32_t insertIndex = result.length(); | |||
1091 | while (_scale > 0) { | |||
1092 | std::div_t res = std::div(_scale, 10); | |||
1093 | result.insert(insertIndex, u'0' + res.rem); | |||
1094 | _scale = res.quot; | |||
1095 | } | |||
1096 | return result; | |||
1097 | } | |||
1098 | ||||
1099 | //////////////////////////////////////////////////// | |||
1100 | /// End of DecimalQuantity_AbstractBCD.java /// | |||
1101 | /// Start of DecimalQuantity_DualStorageBCD.java /// | |||
1102 | //////////////////////////////////////////////////// | |||
1103 | ||||
1104 | int8_t DecimalQuantity::getDigitPos(int32_t position) const { | |||
1105 | if (usingBytes) { | |||
1106 | if (position < 0 || position >= precision) { return 0; } | |||
1107 | return fBCD.bcdBytes.ptr[position]; | |||
1108 | } else { | |||
1109 | if (position < 0 || position >= 16) { return 0; } | |||
1110 | return (int8_t) ((fBCD.bcdLong >> (position * 4)) & 0xf); | |||
1111 | } | |||
1112 | } | |||
1113 | ||||
1114 | void DecimalQuantity::setDigitPos(int32_t position, int8_t value) { | |||
1115 | U_ASSERT(position >= 0)(void)0; | |||
1116 | if (usingBytes) { | |||
1117 | ensureCapacity(position + 1); | |||
1118 | fBCD.bcdBytes.ptr[position] = value; | |||
1119 | } else if (position >= 16) { | |||
1120 | switchStorage(); | |||
1121 | ensureCapacity(position + 1); | |||
1122 | fBCD.bcdBytes.ptr[position] = value; | |||
1123 | } else { | |||
1124 | int shift = position * 4; | |||
1125 | fBCD.bcdLong = (fBCD.bcdLong & ~(0xfL << shift)) | ((long) value << shift); | |||
1126 | } | |||
1127 | } | |||
1128 | ||||
1129 | void DecimalQuantity::shiftLeft(int32_t numDigits) { | |||
1130 | if (!usingBytes && precision + numDigits > 16) { | |||
1131 | switchStorage(); | |||
1132 | } | |||
1133 | if (usingBytes) { | |||
1134 | ensureCapacity(precision + numDigits); | |||
1135 | uprv_memmove(fBCD.bcdBytes.ptr + numDigits, fBCD.bcdBytes.ptr, precision)do { clang diagnostic push
clang diagnostic ignored "-Waddress" (void)0; (void)0; clang diagnostic pop :: memmove(fBCD.bcdBytes .ptr + numDigits, fBCD.bcdBytes.ptr, precision); } while (false ); | |||
1136 | uprv_memset(fBCD.bcdBytes.ptr, 0, numDigits):: memset(fBCD.bcdBytes.ptr, 0, numDigits); | |||
1137 | } else { | |||
1138 | fBCD.bcdLong <<= (numDigits * 4); | |||
1139 | } | |||
1140 | scale -= numDigits; | |||
1141 | precision += numDigits; | |||
1142 | } | |||
1143 | ||||
1144 | void DecimalQuantity::shiftRight(int32_t numDigits) { | |||
1145 | if (usingBytes) { | |||
1146 | int i = 0; | |||
1147 | for (; i < precision - numDigits; i++) { | |||
1148 | fBCD.bcdBytes.ptr[i] = fBCD.bcdBytes.ptr[i + numDigits]; | |||
1149 | } | |||
1150 | for (; i < precision; i++) { | |||
1151 | fBCD.bcdBytes.ptr[i] = 0; | |||
1152 | } | |||
1153 | } else { | |||
1154 | fBCD.bcdLong >>= (numDigits * 4); | |||
1155 | } | |||
1156 | scale += numDigits; | |||
1157 | precision -= numDigits; | |||
1158 | } | |||
1159 | ||||
1160 | void DecimalQuantity::popFromLeft(int32_t numDigits) { | |||
1161 | U_ASSERT(numDigits <= precision)(void)0; | |||
1162 | if (usingBytes) { | |||
1163 | int i = precision - 1; | |||
1164 | for (; i >= precision - numDigits; i--) { | |||
1165 | fBCD.bcdBytes.ptr[i] = 0; | |||
1166 | } | |||
1167 | } else { | |||
1168 | fBCD.bcdLong &= (static_cast<uint64_t>(1) << ((precision - numDigits) * 4)) - 1; | |||
1169 | } | |||
1170 | precision -= numDigits; | |||
1171 | } | |||
1172 | ||||
1173 | void DecimalQuantity::setBcdToZero() { | |||
1174 | if (usingBytes) { | |||
1175 | uprv_freeuprv_free_71(fBCD.bcdBytes.ptr); | |||
1176 | fBCD.bcdBytes.ptr = nullptr; | |||
1177 | usingBytes = false; | |||
1178 | } | |||
1179 | fBCD.bcdLong = 0L; | |||
1180 | scale = 0; | |||
1181 | precision = 0; | |||
1182 | isApproximate = false; | |||
1183 | origDouble = 0; | |||
1184 | origDelta = 0; | |||
1185 | exponent = 0; | |||
1186 | } | |||
1187 | ||||
1188 | void DecimalQuantity::readIntToBcd(int32_t n) { | |||
1189 | U_ASSERT(n != 0)(void)0; | |||
1190 | // ints always fit inside the long implementation. | |||
1191 | uint64_t result = 0L; | |||
1192 | int i = 16; | |||
1193 | for (; n != 0; n /= 10, i--) { | |||
1194 | result = (result >> 4) + ((static_cast<uint64_t>(n) % 10) << 60); | |||
1195 | } | |||
1196 | U_ASSERT(!usingBytes)(void)0; | |||
1197 | fBCD.bcdLong = result >> (i * 4); | |||
| ||||
1198 | scale = 0; | |||
1199 | precision = 16 - i; | |||
1200 | } | |||
1201 | ||||
1202 | void DecimalQuantity::readLongToBcd(int64_t n) { | |||
1203 | U_ASSERT(n != 0)(void)0; | |||
1204 | if (n >= 10000000000000000L) { | |||
1205 | ensureCapacity(); | |||
1206 | int i = 0; | |||
1207 | for (; n != 0L; n /= 10L, i++) { | |||
1208 | fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(n % 10); | |||
1209 | } | |||
1210 | U_ASSERT(usingBytes)(void)0; | |||
1211 | scale = 0; | |||
1212 | precision = i; | |||
1213 | } else { | |||
1214 | uint64_t result = 0L; | |||
1215 | int i = 16; | |||
1216 | for (; n != 0L; n /= 10L, i--) { | |||
1217 | result = (result >> 4) + ((n % 10) << 60); | |||
1218 | } | |||
1219 | U_ASSERT(i >= 0)(void)0; | |||
1220 | U_ASSERT(!usingBytes)(void)0; | |||
1221 | fBCD.bcdLong = result >> (i * 4); | |||
1222 | scale = 0; | |||
1223 | precision = 16 - i; | |||
1224 | } | |||
1225 | } | |||
1226 | ||||
1227 | void DecimalQuantity::readDecNumberToBcd(const DecNum& decnum) { | |||
1228 | const decNumber* dn = decnum.getRawDecNumber(); | |||
1229 | if (dn->digits > 16) { | |||
1230 | ensureCapacity(dn->digits); | |||
1231 | for (int32_t i = 0; i < dn->digits; i++) { | |||
1232 | fBCD.bcdBytes.ptr[i] = dn->lsu[i]; | |||
1233 | } | |||
1234 | } else { | |||
1235 | uint64_t result = 0L; | |||
1236 | for (int32_t i = 0; i < dn->digits; i++) { | |||
1237 | result |= static_cast<uint64_t>(dn->lsu[i]) << (4 * i); | |||
1238 | } | |||
1239 | fBCD.bcdLong = result; | |||
1240 | } | |||
1241 | scale = dn->exponent; | |||
1242 | precision = dn->digits; | |||
1243 | } | |||
1244 | ||||
1245 | void DecimalQuantity::readDoubleConversionToBcd( | |||
1246 | const char* buffer, int32_t length, int32_t point) { | |||
1247 | // NOTE: Despite the fact that double-conversion's API is called | |||
1248 | // "DoubleToAscii", they actually use '0' (as opposed to u8'0'). | |||
1249 | if (length > 16) { | |||
1250 | ensureCapacity(length); | |||
1251 | for (int32_t i = 0; i < length; i++) { | |||
1252 | fBCD.bcdBytes.ptr[i] = buffer[length-i-1] - '0'; | |||
1253 | } | |||
1254 | } else { | |||
1255 | uint64_t result = 0L; | |||
1256 | for (int32_t i = 0; i < length; i++) { | |||
1257 | result |= static_cast<uint64_t>(buffer[length-i-1] - '0') << (4 * i); | |||
1258 | } | |||
1259 | fBCD.bcdLong = result; | |||
1260 | } | |||
1261 | scale = point - length; | |||
1262 | precision = length; | |||
1263 | } | |||
1264 | ||||
1265 | void DecimalQuantity::compact() { | |||
1266 | if (usingBytes) { | |||
1267 | int32_t delta = 0; | |||
1268 | for (; delta < precision && fBCD.bcdBytes.ptr[delta] == 0; delta++); | |||
1269 | if (delta == precision) { | |||
1270 | // Number is zero | |||
1271 | setBcdToZero(); | |||
1272 | return; | |||
1273 | } else { | |||
1274 | // Remove trailing zeros | |||
1275 | shiftRight(delta); | |||
1276 | } | |||
1277 | ||||
1278 | // Compute precision | |||
1279 | int32_t leading = precision - 1; | |||
1280 | for (; leading >= 0 && fBCD.bcdBytes.ptr[leading] == 0; leading--); | |||
1281 | precision = leading + 1; | |||
1282 | ||||
1283 | // Switch storage mechanism if possible | |||
1284 | if (precision <= 16) { | |||
1285 | switchStorage(); | |||
1286 | } | |||
1287 | ||||
1288 | } else { | |||
1289 | if (fBCD.bcdLong == 0L) { | |||
1290 | // Number is zero | |||
1291 | setBcdToZero(); | |||
1292 | return; | |||
1293 | } | |||
1294 | ||||
1295 | // Compact the number (remove trailing zeros) | |||
1296 | // TODO: Use a more efficient algorithm here and below. There is a logarithmic one. | |||
1297 | int32_t delta = 0; | |||
1298 | for (; delta < precision && getDigitPos(delta) == 0; delta++); | |||
1299 | fBCD.bcdLong >>= delta * 4; | |||
1300 | scale += delta; | |||
1301 | ||||
1302 | // Compute precision | |||
1303 | int32_t leading = precision - 1; | |||
1304 | for (; leading >= 0 && getDigitPos(leading) == 0; leading--); | |||
1305 | precision = leading + 1; | |||
1306 | } | |||
1307 | } | |||
1308 | ||||
1309 | void DecimalQuantity::ensureCapacity() { | |||
1310 | ensureCapacity(40); | |||
1311 | } | |||
1312 | ||||
1313 | void DecimalQuantity::ensureCapacity(int32_t capacity) { | |||
1314 | if (capacity == 0) { return; } | |||
1315 | int32_t oldCapacity = usingBytes ? fBCD.bcdBytes.len : 0; | |||
1316 | if (!usingBytes) { | |||
1317 | // TODO: There is nothing being done to check for memory allocation failures. | |||
1318 | // TODO: Consider indexing by nybbles instead of bytes in C++, so that we can | |||
1319 | // make these arrays half the size. | |||
1320 | fBCD.bcdBytes.ptr = static_cast<int8_t*>(uprv_mallocuprv_malloc_71(capacity * sizeof(int8_t))); | |||
1321 | fBCD.bcdBytes.len = capacity; | |||
1322 | // Initialize the byte array to zeros (this is done automatically in Java) | |||
1323 | uprv_memset(fBCD.bcdBytes.ptr, 0, capacity * sizeof(int8_t)):: memset(fBCD.bcdBytes.ptr, 0, capacity * sizeof(int8_t)); | |||
1324 | } else if (oldCapacity < capacity) { | |||
1325 | auto bcd1 = static_cast<int8_t*>(uprv_mallocuprv_malloc_71(capacity * 2 * sizeof(int8_t))); | |||
1326 | uprv_memcpy(bcd1, fBCD.bcdBytes.ptr, oldCapacity * sizeof(int8_t))do { clang diagnostic push
clang diagnostic ignored "-Waddress" (void)0; (void)0; clang diagnostic pop :: memcpy(bcd1, fBCD .bcdBytes.ptr, oldCapacity * sizeof(int8_t)); } while (false); | |||
1327 | // Initialize the rest of the byte array to zeros (this is done automatically in Java) | |||
1328 | uprv_memset(bcd1 + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t)):: memset(bcd1 + oldCapacity, 0, (capacity - oldCapacity) * sizeof (int8_t)); | |||
1329 | uprv_freeuprv_free_71(fBCD.bcdBytes.ptr); | |||
1330 | fBCD.bcdBytes.ptr = bcd1; | |||
1331 | fBCD.bcdBytes.len = capacity * 2; | |||
1332 | } | |||
1333 | usingBytes = true; | |||
1334 | } | |||
1335 | ||||
1336 | void DecimalQuantity::switchStorage() { | |||
1337 | if (usingBytes) { | |||
1338 | // Change from bytes to long | |||
1339 | uint64_t bcdLong = 0L; | |||
1340 | for (int i = precision - 1; i >= 0; i--) { | |||
1341 | bcdLong <<= 4; | |||
1342 | bcdLong |= fBCD.bcdBytes.ptr[i]; | |||
1343 | } | |||
1344 | uprv_freeuprv_free_71(fBCD.bcdBytes.ptr); | |||
1345 | fBCD.bcdBytes.ptr = nullptr; | |||
1346 | fBCD.bcdLong = bcdLong; | |||
1347 | usingBytes = false; | |||
1348 | } else { | |||
1349 | // Change from long to bytes | |||
1350 | // Copy the long into a local variable since it will get munged when we allocate the bytes | |||
1351 | uint64_t bcdLong = fBCD.bcdLong; | |||
1352 | ensureCapacity(); | |||
1353 | for (int i = 0; i < precision; i++) { | |||
1354 | fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(bcdLong & 0xf); | |||
1355 | bcdLong >>= 4; | |||
1356 | } | |||
1357 | U_ASSERT(usingBytes)(void)0; | |||
1358 | } | |||
1359 | } | |||
1360 | ||||
1361 | void DecimalQuantity::copyBcdFrom(const DecimalQuantity &other) { | |||
1362 | setBcdToZero(); | |||
1363 | if (other.usingBytes) { | |||
1364 | ensureCapacity(other.precision); | |||
1365 | uprv_memcpy(fBCD.bcdBytes.ptr, other.fBCD.bcdBytes.ptr, other.precision * sizeof(int8_t))do { clang diagnostic push
clang diagnostic ignored "-Waddress" (void)0; (void)0; clang diagnostic pop :: memcpy(fBCD.bcdBytes .ptr, other.fBCD.bcdBytes.ptr, other.precision * sizeof(int8_t )); } while (false); | |||
1366 | } else { | |||
1367 | fBCD.bcdLong = other.fBCD.bcdLong; | |||
1368 | } | |||
1369 | } | |||
1370 | ||||
1371 | void DecimalQuantity::moveBcdFrom(DecimalQuantity &other) { | |||
1372 | setBcdToZero(); | |||
1373 | if (other.usingBytes) { | |||
1374 | usingBytes = true; | |||
1375 | fBCD.bcdBytes.ptr = other.fBCD.bcdBytes.ptr; | |||
1376 | fBCD.bcdBytes.len = other.fBCD.bcdBytes.len; | |||
1377 | // Take ownership away from the old instance: | |||
1378 | other.fBCD.bcdBytes.ptr = nullptr; | |||
1379 | other.usingBytes = false; | |||
1380 | } else { | |||
1381 | fBCD.bcdLong = other.fBCD.bcdLong; | |||
1382 | } | |||
1383 | } | |||
1384 | ||||
1385 | const char16_t* DecimalQuantity::checkHealth() const { | |||
1386 | if (usingBytes) { | |||
1387 | if (precision == 0) { return u"Zero precision but we are in byte mode"; } | |||
1388 | int32_t capacity = fBCD.bcdBytes.len; | |||
1389 | if (precision > capacity) { return u"Precision exceeds length of byte array"; } | |||
1390 | if (getDigitPos(precision - 1) == 0) { return u"Most significant digit is zero in byte mode"; } | |||
1391 | if (getDigitPos(0) == 0) { return u"Least significant digit is zero in long mode"; } | |||
1392 | for (int i = 0; i < precision; i++) { | |||
1393 | if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in byte array"; } | |||
1394 | if (getDigitPos(i) < 0) { return u"Digit below 0 in byte array"; } | |||
1395 | } | |||
1396 | for (int i = precision; i < capacity; i++) { | |||
1397 | if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in byte array"; } | |||
1398 | } | |||
1399 | } else { | |||
1400 | if (precision == 0 && fBCD.bcdLong != 0) { | |||
1401 | return u"Value in bcdLong even though precision is zero"; | |||
1402 | } | |||
1403 | if (precision > 16) { return u"Precision exceeds length of long"; } | |||
1404 | if (precision != 0 && getDigitPos(precision - 1) == 0) { | |||
1405 | return u"Most significant digit is zero in long mode"; | |||
1406 | } | |||
1407 | if (precision != 0 && getDigitPos(0) == 0) { | |||
1408 | return u"Least significant digit is zero in long mode"; | |||
1409 | } | |||
1410 | for (int i = 0; i < precision; i++) { | |||
1411 | if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in long"; } | |||
1412 | if (getDigitPos(i) < 0) { return u"Digit below 0 in long (?!)"; } | |||
1413 | } | |||
1414 | for (int i = precision; i < 16; i++) { | |||
1415 | if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in long"; } | |||
1416 | } | |||
1417 | } | |||
1418 | ||||
1419 | // No error | |||
1420 | return nullptr; | |||
1421 | } | |||
1422 | ||||
1423 | bool DecimalQuantity::operator==(const DecimalQuantity& other) const { | |||
1424 | bool basicEquals = | |||
1425 | scale == other.scale | |||
1426 | && precision == other.precision | |||
1427 | && flags == other.flags | |||
1428 | && lReqPos == other.lReqPos | |||
1429 | && rReqPos == other.rReqPos | |||
1430 | && isApproximate == other.isApproximate; | |||
1431 | if (!basicEquals) { | |||
1432 | return false; | |||
1433 | } | |||
1434 | ||||
1435 | if (precision == 0) { | |||
1436 | return true; | |||
1437 | } else if (isApproximate) { | |||
1438 | return origDouble == other.origDouble && origDelta == other.origDelta; | |||
1439 | } else { | |||
1440 | for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) { | |||
1441 | if (getDigit(m) != other.getDigit(m)) { | |||
1442 | return false; | |||
1443 | } | |||
1444 | } | |||
1445 | return true; | |||
1446 | } | |||
1447 | } | |||
1448 | ||||
1449 | UnicodeString DecimalQuantity::toString() const { | |||
1450 | UErrorCode localStatus = U_ZERO_ERROR; | |||
1451 | MaybeStackArray<char, 30> digits(precision + 1, localStatus); | |||
1452 | if (U_FAILURE(localStatus)) { | |||
1453 | return ICU_Utility::makeBogusString(); | |||
1454 | } | |||
1455 | for (int32_t i = 0; i < precision; i++) { | |||
1456 | digits[i] = getDigitPos(precision - i - 1) + '0'; | |||
1457 | } | |||
1458 | digits[precision] = 0; // terminate buffer | |||
1459 | char buffer8[100]; | |||
1460 | snprintf( | |||
1461 | buffer8, | |||
1462 | sizeof(buffer8), | |||
1463 | "<DecimalQuantity %d:%d %s %s%s%s%d>", | |||
1464 | lReqPos, | |||
1465 | rReqPos, | |||
1466 | (usingBytes ? "bytes" : "long"), | |||
1467 | (isNegative() ? "-" : ""), | |||
1468 | (precision == 0 ? "0" : digits.getAlias()), | |||
1469 | "E", | |||
1470 | scale); | |||
1471 | return UnicodeString(buffer8, -1, US_INVicu::UnicodeString::kInvariant); | |||
1472 | } | |||
1473 | ||||
1474 | #endif /* #if !UCONFIG_NO_FORMATTING */ |