1 /*
2 **********************************************************************
3 * Copyright (C) 1997-2010, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
6 *
7 * File DIGITLST.CPP
8 *
9 * Modification History:
10 *
11 * Date Name Description
12 * 03/21/97 clhuang Converted from java.
13 * 03/21/97 clhuang Implemented with new APIs.
14 * 03/27/97 helena Updated to pass the simple test after code review.
15 * 03/31/97 aliu Moved isLONG_MIN to here, and fixed it.
16 * 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char.
17 * Reworked representation by replacing fDecimalAt
18 * with fExponent.
19 * 04/16/97 aliu Rewrote set() and getDouble() to use sprintf/atof
20 * to do digit conversion.
21 * 09/09/97 aliu Modified for exponential notation support.
22 * 08/02/98 stephen Added nearest/even rounding
23 * Fixed bug in fitsIntoLong
24 ******************************************************************************
25 */
26
27 #include "digitlst.h"
28
29 #if !UCONFIG_NO_FORMATTING
30 #include "unicode/putil.h"
31 #include "charstr.h"
32 #include "cmemory.h"
33 #include "cstring.h"
34 #include "putilimp.h"
35 #include "uassert.h"
36 #include <stdlib.h>
37 #include <limits.h>
38 #include <string.h>
39 #include <stdio.h>
40 #ifdef ANDROID
41 #include <math.h>
42 #else
43 #include <limits>
44 #endif
45
46 // ***************************************************************************
47 // class DigitList
48 // A wrapper onto decNumber.
49 // Used to be standalone.
50 // ***************************************************************************
51
52 /**
53 * This is the zero digit. The base for the digits returned by getDigit()
54 * Note that it is the platform invariant digit, and is not Unicode.
55 */
56 #define kZero '0'
57
58 static char gDecimal = 0;
59
60 /* Only for 32 bit numbers. Ignore the negative sign. */
61 static const char LONG_MIN_REP[] = "2147483648";
62 static const char I64_MIN_REP[] = "9223372036854775808";
63
64
65 U_NAMESPACE_BEGIN
66
67 // -------------------------------------
68 // default constructor
69
DigitList()70 DigitList::DigitList()
71 {
72 uprv_decContextDefault(&fContext, DEC_INIT_BASE);
73 fContext.traps = 0;
74 uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
75 fContext.digits = fStorage.getCapacity();
76
77 fDecNumber = fStorage.getAlias();
78 uprv_decNumberZero(fDecNumber);
79
80 fDouble = 0.0;
81 fHaveDouble = TRUE;
82 }
83
84 // -------------------------------------
85
~DigitList()86 DigitList::~DigitList()
87 {
88 }
89
90 // -------------------------------------
91 // copy constructor
92
DigitList(const DigitList & other)93 DigitList::DigitList(const DigitList &other)
94 {
95 fDecNumber = fStorage.getAlias();
96 *this = other;
97 }
98
99
100 // -------------------------------------
101 // assignment operator
102
103 DigitList&
operator =(const DigitList & other)104 DigitList::operator=(const DigitList& other)
105 {
106 if (this != &other)
107 {
108 uprv_memcpy(&fContext, &other.fContext, sizeof(decContext));
109
110 if (other.fStorage.getCapacity() > fStorage.getCapacity()) {
111 fDecNumber = fStorage.resize(other.fStorage.getCapacity());
112 }
113 // Always reset the fContext.digits, even if fDecNumber was not reallocated,
114 // because above we copied fContext from other.fContext.
115 fContext.digits = fStorage.getCapacity();
116 uprv_decNumberCopy(fDecNumber, other.fDecNumber);
117
118 fDouble = other.fDouble;
119 fHaveDouble = other.fHaveDouble;
120 }
121 return *this;
122 }
123
124 // -------------------------------------
125 // operator == (does not exactly match the old DigitList function)
126
127 UBool
operator ==(const DigitList & that) const128 DigitList::operator==(const DigitList& that) const
129 {
130 if (this == &that) {
131 return TRUE;
132 }
133 decNumber n; // Has space for only a none digit value.
134 decContext c;
135 uprv_decContextDefault(&c, DEC_INIT_BASE);
136 c.digits = 1;
137 c.traps = 0;
138
139 uprv_decNumberCompare(&n, this->fDecNumber, that.fDecNumber, &c);
140 UBool result = decNumberIsZero(&n);
141 return result;
142 }
143
144 // -------------------------------------
145 // comparison function. Returns
146 // Not Comparable : -2
147 // < : -1
148 // == : 0
149 // > : +1
compare(const DigitList & other)150 int32_t DigitList::compare(const DigitList &other) {
151 decNumber result;
152 int32_t savedDigits = fContext.digits;
153 fContext.digits = 1;
154 uprv_decNumberCompare(&result, this->fDecNumber, other.fDecNumber, &fContext);
155 fContext.digits = savedDigits;
156 if (decNumberIsZero(&result)) {
157 return 0;
158 } else if (decNumberIsSpecial(&result)) {
159 return -2;
160 } else if (result.bits & DECNEG) {
161 return -1;
162 } else {
163 return 1;
164 }
165 }
166
167
168 // -------------------------------------
169 // Reduce - remove trailing zero digits.
170 void
reduce()171 DigitList::reduce() {
172 uprv_decNumberReduce(fDecNumber, fDecNumber, &fContext);
173 }
174
175
176 // -------------------------------------
177 // trim - remove trailing fraction zero digits.
178 void
trim()179 DigitList::trim() {
180 uprv_decNumberTrim(fDecNumber);
181 }
182
183 // -------------------------------------
184 // Resets the digit list; sets all the digits to zero.
185
186 void
clear()187 DigitList::clear()
188 {
189 uprv_decNumberZero(fDecNumber);
190 uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
191 fDouble = 0.0;
192 fHaveDouble = TRUE;
193 }
194
195
196 /**
197 * Formats a int64_t number into a base 10 string representation, and NULL terminates it.
198 * @param number The number to format
199 * @param outputStr The string to output to. Must be at least MAX_DIGITS+2 in length (21),
200 * to hold the longest int64_t value.
201 * @return the number of digits written, not including the sign.
202 */
203 static int32_t
formatBase10(int64_t number,char * outputStr)204 formatBase10(int64_t number, char *outputStr) {
205 // The number is output backwards, starting with the LSD.
206 // Fill the buffer from the far end. After the number is complete,
207 // slide the string contents to the front.
208
209 const int32_t MAX_IDX = MAX_DIGITS+2;
210 int32_t destIdx = MAX_IDX;
211 outputStr[--destIdx] = 0;
212
213 int64_t n = number;
214 if (number < 0) { // Negative numbers are slightly larger than a postive
215 outputStr[--destIdx] = (char)(-(n % 10) + kZero);
216 n /= -10;
217 }
218 do {
219 outputStr[--destIdx] = (char)(n % 10 + kZero);
220 n /= 10;
221 } while (n > 0);
222
223 if (number < 0) {
224 outputStr[--destIdx] = '-';
225 }
226
227 // Slide the number to the start of the output str
228 U_ASSERT(destIdx >= 0);
229 int32_t length = MAX_IDX - destIdx;
230 uprv_memmove(outputStr, outputStr+MAX_IDX-length, length);
231
232 return length;
233 }
234
235
236 // -------------------------------------
237
238 void
setRoundingMode(DecimalFormat::ERoundingMode m)239 DigitList::setRoundingMode(DecimalFormat::ERoundingMode m) {
240 enum rounding r;
241
242 switch (m) {
243 case DecimalFormat::kRoundCeiling: r = DEC_ROUND_CEILING; break;
244 case DecimalFormat::kRoundFloor: r = DEC_ROUND_FLOOR; break;
245 case DecimalFormat::kRoundDown: r = DEC_ROUND_DOWN; break;
246 case DecimalFormat::kRoundUp: r = DEC_ROUND_UP; break;
247 case DecimalFormat::kRoundHalfEven: r = DEC_ROUND_HALF_EVEN; break;
248 case DecimalFormat::kRoundHalfDown: r = DEC_ROUND_HALF_DOWN; break;
249 case DecimalFormat::kRoundHalfUp: r = DEC_ROUND_HALF_UP; break;
250 default:
251 // TODO: how to report the problem?
252 // Leave existing mode unchanged.
253 r = uprv_decContextGetRounding(&fContext);
254 }
255 uprv_decContextSetRounding(&fContext, r);
256
257 }
258
259
260 // -------------------------------------
261
262 void
setPositive(UBool s)263 DigitList::setPositive(UBool s) {
264 if (s) {
265 fDecNumber->bits &= ~DECNEG;
266 } else {
267 fDecNumber->bits |= DECNEG;
268 }
269 fHaveDouble = FALSE;
270 }
271 // -------------------------------------
272
273 void
setDecimalAt(int32_t d)274 DigitList::setDecimalAt(int32_t d) {
275 U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0); // Not Infinity or NaN
276 U_ASSERT(d-1>-999999999);
277 U_ASSERT(d-1< 999999999);
278 int32_t adjustedDigits = fDecNumber->digits;
279 if (decNumberIsZero(fDecNumber)) {
280 // Account for difference in how zero is represented between DigitList & decNumber.
281 adjustedDigits = 0;
282 }
283 fDecNumber->exponent = d - adjustedDigits;
284 fHaveDouble = FALSE;
285 }
286
287 int32_t
getDecimalAt()288 DigitList::getDecimalAt() {
289 U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0); // Not Infinity or NaN
290 if (decNumberIsZero(fDecNumber) || ((fDecNumber->bits & DECSPECIAL) != 0)) {
291 return fDecNumber->exponent; // Exponent should be zero for these cases.
292 }
293 return fDecNumber->exponent + fDecNumber->digits;
294 }
295
296 void
setCount(int32_t c)297 DigitList::setCount(int32_t c) {
298 U_ASSERT(c <= fContext.digits);
299 if (c == 0) {
300 // For a value of zero, DigitList sets all fields to zero, while
301 // decNumber keeps one digit (with that digit being a zero)
302 c = 1;
303 fDecNumber->lsu[0] = 0;
304 }
305 fDecNumber->digits = c;
306 fHaveDouble = FALSE;
307 }
308
309 int32_t
getCount() const310 DigitList::getCount() const {
311 if (decNumberIsZero(fDecNumber) && fDecNumber->exponent==0) {
312 // The extra test for exponent==0 is needed because parsing sometimes appends
313 // zero digits. It's bogus, decimalFormatter parsing needs to be cleaned up.
314 return 0;
315 } else {
316 return fDecNumber->digits;
317 }
318 }
319
320 void
setDigit(int32_t i,char v)321 DigitList::setDigit(int32_t i, char v) {
322 int32_t count = fDecNumber->digits;
323 U_ASSERT(i<count);
324 U_ASSERT(v>='0' && v<='9');
325 v &= 0x0f;
326 fDecNumber->lsu[count-i-1] = v;
327 fHaveDouble = FALSE;
328 }
329
330 char
getDigit(int32_t i)331 DigitList::getDigit(int32_t i) {
332 int32_t count = fDecNumber->digits;
333 U_ASSERT(i<count);
334 return fDecNumber->lsu[count-i-1] + '0';
335 }
336
337 // copied from DigitList::getDigit()
338 uint8_t
getDigitValue(int32_t i)339 DigitList::getDigitValue(int32_t i) {
340 int32_t count = fDecNumber->digits;
341 U_ASSERT(i<count);
342 return fDecNumber->lsu[count-i-1];
343 }
344
345 // -------------------------------------
346 // Appends the digit to the digit list if it's not out of scope.
347 // Ignores the digit, otherwise.
348 //
349 // This function is horribly inefficient to implement with decNumber because
350 // the digits are stored least significant first, which requires moving all
351 // existing digits down one to make space for the new one to be appended.
352 //
353 void
append(char digit)354 DigitList::append(char digit)
355 {
356 U_ASSERT(digit>='0' && digit<='9');
357 // Ignore digits which exceed the precision we can represent
358 // And don't fix for larger precision. Fix callers instead.
359 if (decNumberIsZero(fDecNumber)) {
360 // Zero needs to be special cased because of the difference in the way
361 // that the old DigitList and decNumber represent it.
362 // digit cout was zero for digitList, is one for decNumber
363 fDecNumber->lsu[0] = digit & 0x0f;
364 fDecNumber->digits = 1;
365 fDecNumber->exponent--; // To match the old digit list implementation.
366 } else {
367 int32_t nDigits = fDecNumber->digits;
368 if (nDigits < fContext.digits) {
369 int i;
370 for (i=nDigits; i>0; i--) {
371 fDecNumber->lsu[i] = fDecNumber->lsu[i-1];
372 }
373 fDecNumber->lsu[0] = digit & 0x0f;
374 fDecNumber->digits++;
375 // DigitList emulation - appending doesn't change the magnitude of existing
376 // digits. With decNumber's decimal being after the
377 // least signficant digit, we need to adjust the exponent.
378 fDecNumber->exponent--;
379 }
380 }
381 fHaveDouble = FALSE;
382 }
383
384 // -------------------------------------
385
386 /**
387 * Currently, getDouble() depends on atof() to do its conversion.
388 *
389 * WARNING!!
390 * This is an extremely costly function. ~1/2 of the conversion time
391 * can be linked to this function.
392 */
393 double
getDouble() const394 DigitList::getDouble() const
395 {
396 // TODO: fix thread safety. Can probably be finessed some by analyzing
397 // what public const functions can see which DigitLists.
398 // Like precompute fDouble for DigitLists coming in from a parse
399 // or from a Formattable::set(), but not for any others.
400 if (fHaveDouble) {
401 return fDouble;
402 }
403 DigitList *nonConstThis = const_cast<DigitList *>(this);
404
405 if (gDecimal == 0) {
406 char rep[MAX_DIGITS];
407 // For machines that decide to change the decimal on you,
408 // and try to be too smart with localization.
409 // This normally should be just a '.'.
410 sprintf(rep, "%+1.1f", 1.0);
411 gDecimal = rep[2];
412 }
413
414 if (isZero()) {
415 nonConstThis->fDouble = 0.0;
416 if (decNumberIsNegative(fDecNumber)) {
417 nonConstThis->fDouble /= -1;
418 }
419 } else if (isInfinite()) {
420 // BEGIN android-changed
421 // There is no numeric_limits template member in Android std nor
422 // INFINITY defined in math.h of ICU Linux build.
423 #ifdef INFINITY
424 nonConstThis->fDouble = INFINITY;
425 #else
426 if (std::numeric_limits<double>::has_infinity) {
427 nonConstThis->fDouble = std::numeric_limits<double>::infinity();
428 } else {
429 nonConstThis->fDouble = std::numeric_limits<double>::max();
430 }
431 #endif
432 // END android-changed
433
434 if (!isPositive()) {
435 nonConstThis->fDouble = -fDouble;
436 }
437 } else {
438 MaybeStackArray<char, MAX_DBL_DIGITS+18> s;
439 // Note: 14 is a magic constant from the decNumber library documentation,
440 // the max number of extra characters beyond the number of digits
441 // needed to represent the number in string form. Add a few more
442 // for the additional digits we retain.
443
444 // Round down to appx. double precision, if the number is longer than that.
445 // Copy the number first, so that we don't modify the original.
446 if (getCount() > MAX_DBL_DIGITS + 3) {
447 DigitList numToConvert(*this);
448 numToConvert.reduce(); // Removes any trailing zeros, so that digit count is good.
449 numToConvert.round(MAX_DBL_DIGITS+3);
450 uprv_decNumberToString(numToConvert.fDecNumber, s);
451 // TODO: how many extra digits should be included for an accurate conversion?
452 } else {
453 uprv_decNumberToString(this->fDecNumber, s);
454 }
455 U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18);
456
457 if (gDecimal != '.') {
458 char *decimalPt = strchr(s, '.');
459 if (decimalPt != NULL) {
460 *decimalPt = gDecimal;
461 }
462 }
463 char *end = NULL;
464 nonConstThis->fDouble = uprv_strtod(s, &end);
465 }
466 nonConstThis->fHaveDouble = TRUE;
467 return fDouble;
468 }
469
470 // -------------------------------------
471
472 /**
473 * convert this number to an int32_t. Round if there is a fractional part.
474 * Return zero if the number cannot be represented.
475 */
getLong()476 int32_t DigitList::getLong() /*const*/
477 {
478 int32_t result = 0;
479 if (fDecNumber->digits + fDecNumber->exponent > 10) {
480 // Overflow, absolute value too big.
481 return result;
482 }
483 if (fDecNumber->exponent != 0) {
484 // Force to an integer, with zero exponent, rounding if necessary.
485 // (decNumberToInt32 will only work if the exponent is exactly zero.)
486 DigitList copy(*this);
487 DigitList zero;
488 uprv_decNumberQuantize(copy.fDecNumber, copy.fDecNumber, zero.fDecNumber, &fContext);
489 result = uprv_decNumberToInt32(copy.fDecNumber, &fContext);
490 } else {
491 result = uprv_decNumberToInt32(fDecNumber, &fContext);
492 }
493 return result;
494 }
495
496 /**
497 * convert this number to an int64_t. Truncate if there is a fractional part.
498 * Return zero if the number cannot be represented.
499 */
getInt64()500 int64_t DigitList::getInt64() /*const*/ {
501 // BEGIN android-change
502 // Apply the changes for ICU ticket#8199 to avoid the crash in DigitList::getInt64().
503 // The fixes are in ICU4.8.
504 // See http://bugs.icu-project.org/trac/ticket/8199 for details.
505
506 // Truncate if non-integer.
507 // Return 0 if out of range.
508 // Range of in64_t is -9223372036854775808 to 9223372036854775807 (19 digits)
509 //
510 if (fDecNumber->digits + fDecNumber->exponent > 19) {
511 // Overflow, absolute value too big.
512 return 0;
513 }
514
515 // The number of integer digits may differ from the number of digits stored
516 // in the decimal number.
517 // for 12.345 numIntDigits = 2, number->digits = 5
518 // for 12E4 numIntDigits = 6, number->digits = 2
519 // The conversion ignores the fraction digits in the first case,
520 // and fakes up extra zero digits in the second.
521 // TODO: It would be faster to store a table of powers of ten to multiply by
522 // instead of looping over zero digits, multiplying each time.
523
524 int32_t numIntDigits = fDecNumber->digits + fDecNumber->exponent;
525 uint64_t value = 0;
526 for (int32_t i = 0; i < numIntDigits; i++) {
527 // Loop is iterating over digits starting with the most significant.
528 // Numbers are stored with the least significant digit at index zero.
529 int32_t digitIndex = fDecNumber->digits - i - 1;
530 int32_t v = (digitIndex >= 0) ? fDecNumber->lsu[digitIndex] : 0;
531 value = value * (uint64_t)10 + (uint64_t)v;
532 }
533
534 if (decNumberIsNegative(fDecNumber)) {
535 value = ~value;
536 value += 1;
537 }
538 int64_t svalue = (int64_t)value;
539
540 // Check overflow. It's convenient that the MSD is 9 only on overflow, the amount of
541 // overflow can't wrap too far. The test will also fail -0, but
542 // that does no harm; the right answer is 0.
543 if (numIntDigits == 19) {
544 if (( decNumberIsNegative(fDecNumber) && svalue>0) ||
545 (!decNumberIsNegative(fDecNumber) && svalue<0)) {
546 svalue = 0;
547 }
548 }
549 // END android-change
550
551 return svalue;
552 }
553
554 /**
555 * Return a string form of this number.
556 * Format is as defined by the decNumber library, for interchange of
557 * decimal numbers.
558 */
getDecimal(CharString & str,UErrorCode & status)559 void DigitList::getDecimal(CharString &str, UErrorCode &status) {
560 if (U_FAILURE(status)) {
561 return;
562 }
563
564 // A decimal number in string form can, worst case, be 14 characters longer
565 // than the number of digits. So says the decNumber library doc.
566 int32_t maxLength = fDecNumber->digits + 14;
567 int32_t capacity = 0;
568 char *buffer = str.clear().getAppendBuffer(maxLength, 0, capacity, status);
569 if (U_FAILURE(status)) {
570 return; // Memory allocation error on growing the string.
571 }
572 U_ASSERT(capacity >= maxLength);
573 uprv_decNumberToString(this->fDecNumber, buffer);
574 U_ASSERT((int32_t)uprv_strlen(buffer) <= maxLength);
575 str.append(buffer, -1, status);
576 }
577
578 /**
579 * Return true if this is an integer value that can be held
580 * by an int32_t type.
581 */
582 UBool
fitsIntoLong(UBool ignoreNegativeZero)583 DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/
584 {
585 if (decNumberIsSpecial(this->fDecNumber)) {
586 // NaN or Infinity. Does not fit in int32.
587 return FALSE;
588 }
589 uprv_decNumberTrim(this->fDecNumber);
590 if (fDecNumber->exponent < 0) {
591 // Number contains fraction digits.
592 return FALSE;
593 }
594 if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
595 (fDecNumber->bits & DECNEG) != 0) {
596 // Negative Zero, not ingored. Cannot represent as a long.
597 return FALSE;
598 }
599 if (fDecNumber->digits + fDecNumber->exponent < 10) {
600 // The number is 9 or fewer digits.
601 // The max and min int32 are 10 digts, so this number fits.
602 // This is the common case.
603 return TRUE;
604 }
605
606 // TODO: Should cache these constants; construction is relatively costly.
607 // But not of huge consequence; they're only needed for 10 digit ints.
608 UErrorCode status = U_ZERO_ERROR;
609 DigitList min32; min32.set("-2147483648", status);
610 if (this->compare(min32) < 0) {
611 return FALSE;
612 }
613 DigitList max32; max32.set("2147483647", status);
614 if (this->compare(max32) > 0) {
615 return FALSE;
616 }
617 if (U_FAILURE(status)) {
618 return FALSE;
619 }
620 return true;
621 }
622
623
624
625 /**
626 * Return true if the number represented by this object can fit into
627 * a long.
628 */
629 UBool
fitsIntoInt64(UBool ignoreNegativeZero)630 DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/
631 {
632 if (decNumberIsSpecial(this->fDecNumber)) {
633 // NaN or Infinity. Does not fit in int32.
634 return FALSE;
635 }
636 uprv_decNumberTrim(this->fDecNumber);
637 if (fDecNumber->exponent < 0) {
638 // Number contains fraction digits.
639 return FALSE;
640 }
641 if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
642 (fDecNumber->bits & DECNEG) != 0) {
643 // Negative Zero, not ingored. Cannot represent as a long.
644 return FALSE;
645 }
646 if (fDecNumber->digits + fDecNumber->exponent < 19) {
647 // The number is 18 or fewer digits.
648 // The max and min int64 are 19 digts, so this number fits.
649 // This is the common case.
650 return TRUE;
651 }
652
653 // TODO: Should cache these constants; construction is relatively costly.
654 // But not of huge consequence; they're only needed for 19 digit ints.
655 UErrorCode status = U_ZERO_ERROR;
656 DigitList min64; min64.set("-9223372036854775808", status);
657 if (this->compare(min64) < 0) {
658 return FALSE;
659 }
660 DigitList max64; max64.set("9223372036854775807", status);
661 if (this->compare(max64) > 0) {
662 return FALSE;
663 }
664 if (U_FAILURE(status)) {
665 return FALSE;
666 }
667 return true;
668 }
669
670
671 // -------------------------------------
672
673 void
set(int32_t source)674 DigitList::set(int32_t source)
675 {
676 set((int64_t)source);
677 fDouble = source;
678 fHaveDouble = TRUE;
679 }
680
681 // -------------------------------------
682 /**
683 * @param maximumDigits The maximum digits to be generated. If zero,
684 * there is no maximum -- generate all digits.
685 */
686 void
set(int64_t source)687 DigitList::set(int64_t source)
688 {
689 char str[MAX_DIGITS+2]; // Leave room for sign and trailing nul.
690 formatBase10(source, str);
691 U_ASSERT(uprv_strlen(str) < sizeof(str));
692
693 uprv_decNumberFromString(fDecNumber, str, &fContext);
694 fDouble = (double)source;
695 fHaveDouble = TRUE;
696 }
697
698
699 // -------------------------------------
700 /**
701 * Set the DigitList from a decimal number string.
702 *
703 * The incoming string _must_ be nul terminated, even though it is arriving
704 * as a StringPiece because that is what the decNumber library wants.
705 * We can get away with this for an internal function; it would not
706 * be acceptable for a public API.
707 */
708 void
set(const StringPiece & source,UErrorCode & status)709 DigitList::set(const StringPiece &source, UErrorCode &status) {
710 if (U_FAILURE(status)) {
711 return;
712 }
713
714 // Figure out a max number of digits to use during the conversion, and
715 // resize the number up if necessary.
716 int32_t numDigits = source.length();
717 if (numDigits > fContext.digits) {
718 // fContext.digits == fStorage.getCapacity()
719 decNumber *t = fStorage.resize(numDigits, fStorage.getCapacity());
720 if (t == NULL) {
721 status = U_MEMORY_ALLOCATION_ERROR;
722 return;
723 }
724 fDecNumber = t;
725 fContext.digits = numDigits;
726 }
727
728 fContext.status = 0;
729 uprv_decNumberFromString(fDecNumber, source.data(), &fContext);
730 if ((fContext.status & DEC_Conversion_syntax) != 0) {
731 status = U_DECIMAL_NUMBER_SYNTAX_ERROR;
732 }
733 fHaveDouble = FALSE;
734 }
735
736 /**
737 * Set the digit list to a representation of the given double value.
738 * This method supports both fixed-point and exponential notation.
739 * @param source Value to be converted.
740 */
741 void
set(double source)742 DigitList::set(double source)
743 {
744 // for now, simple implementation; later, do proper IEEE stuff
745 char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough)
746
747 // Generate a representation of the form /[+-][0-9]+e[+-][0-9]+/
748 sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source);
749 U_ASSERT(uprv_strlen(rep) < sizeof(rep));
750
751 // Create a decNumber from the string.
752 uprv_decNumberFromString(fDecNumber, rep, &fContext);
753 uprv_decNumberTrim(fDecNumber);
754 fDouble = source;
755 fHaveDouble = TRUE;
756 }
757
758 // -------------------------------------
759
760 /*
761 * Multiply
762 * The number will be expanded if need be to retain full precision.
763 * In practice, for formatting, multiply is by 10, 100 or 1000, so more digits
764 * will not be required for this use.
765 */
766 void
mult(const DigitList & other,UErrorCode & status)767 DigitList::mult(const DigitList &other, UErrorCode &status) {
768 fContext.status = 0;
769 int32_t requiredDigits = this->digits() + other.digits();
770 if (requiredDigits > fContext.digits) {
771 reduce(); // Remove any trailing zeros
772 int32_t requiredDigits = this->digits() + other.digits();
773 ensureCapacity(requiredDigits, status);
774 }
775 uprv_decNumberMultiply(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
776 fHaveDouble = FALSE;
777 }
778
779 // -------------------------------------
780
781 /*
782 * Divide
783 * The number will _not_ be expanded for inexact results.
784 * TODO: probably should expand some, for rounding increments that
785 * could add a few digits, e.g. .25, but not expand arbitrarily.
786 */
787 void
div(const DigitList & other,UErrorCode & status)788 DigitList::div(const DigitList &other, UErrorCode &status) {
789 if (U_FAILURE(status)) {
790 return;
791 }
792 uprv_decNumberDivide(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
793 fHaveDouble = FALSE;
794 }
795
796 // -------------------------------------
797
798 /*
799 * ensureCapacity. Grow the digit storage for the number if it's less than the requested
800 * amount. Never reduce it. Available size is kept in fContext.digits.
801 */
802 void
ensureCapacity(int32_t requestedCapacity,UErrorCode & status)803 DigitList::ensureCapacity(int32_t requestedCapacity, UErrorCode &status) {
804 if (U_FAILURE(status)) {
805 return;
806 }
807 if (requestedCapacity <= 0) {
808 status = U_ILLEGAL_ARGUMENT_ERROR;
809 return;
810 }
811 if (requestedCapacity > DEC_MAX_DIGITS) {
812 // Don't report an error for requesting too much.
813 // Arithemetic Results will be rounded to what can be supported.
814 // At 999,999,999 max digits, exceeding the limit is not too likely!
815 requestedCapacity = DEC_MAX_DIGITS;
816 }
817 if (requestedCapacity > fContext.digits) {
818 decNumber *newBuffer = fStorage.resize(requestedCapacity, fStorage.getCapacity());
819 if (newBuffer == NULL) {
820 status = U_MEMORY_ALLOCATION_ERROR;
821 return;
822 }
823 fContext.digits = requestedCapacity;
824 fDecNumber = newBuffer;
825 }
826 }
827
828 // -------------------------------------
829
830 /**
831 * Round the representation to the given number of digits.
832 * @param maximumDigits The maximum number of digits to be shown.
833 * Upon return, count will be less than or equal to maximumDigits.
834 */
835 void
round(int32_t maximumDigits)836 DigitList::round(int32_t maximumDigits)
837 {
838 int32_t savedDigits = fContext.digits;
839 fContext.digits = maximumDigits;
840 uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext);
841 fContext.digits = savedDigits;
842 uprv_decNumberTrim(fDecNumber);
843 fHaveDouble = FALSE;
844 }
845
846
847 void
roundFixedPoint(int32_t maximumFractionDigits)848 DigitList::roundFixedPoint(int32_t maximumFractionDigits) {
849 trim(); // Remove trailing zeros.
850 if (fDecNumber->exponent >= -maximumFractionDigits) {
851 return;
852 }
853 decNumber scale; // Dummy decimal number, but with the desired number of
854 uprv_decNumberZero(&scale); // fraction digits.
855 scale.exponent = -maximumFractionDigits;
856 scale.lsu[0] = 1;
857
858 uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext);
859 trim();
860 fHaveDouble = FALSE;
861 }
862
863 // -------------------------------------
864
865 void
toIntegralValue()866 DigitList::toIntegralValue() {
867 uprv_decNumberToIntegralValue(fDecNumber, fDecNumber, &fContext);
868 }
869
870
871 // -------------------------------------
872 UBool
isZero() const873 DigitList::isZero() const
874 {
875 return decNumberIsZero(fDecNumber);
876 }
877
878
879 U_NAMESPACE_END
880 #endif // #if !UCONFIG_NO_FORMATTING
881
882 //eof
883