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