• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 **********************************************************************
3 *   Copyright (C) 1997-2007, 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 "cstring.h"
32 #include "putilimp.h"
33 #include "uassert.h"
34 #include <stdlib.h>
35 #include <limits.h>
36 #include <string.h>
37 #include <stdio.h>
38 
39 // ***************************************************************************
40 // class DigitList
41 // This class handles the transcoding between numeric values and strings of
42 //  characters.  Only handles as non-negative numbers.
43 // ***************************************************************************
44 
45 /**
46  * This is the zero digit.  Array elements fDigits[i] have values from
47  * kZero to kZero + 9.  Typically, this is '0'.
48  */
49 #define kZero '0'
50 
51 static char gDecimal = 0;
52 
53 /* Only for 32 bit numbers. Ignore the negative sign. */
54 static const char LONG_MIN_REP[] = "2147483648";
55 static const char I64_MIN_REP[] = "9223372036854775808";
56 
57 enum {
58     LONG_MIN_REP_LENGTH = sizeof(LONG_MIN_REP) - 1, //Ignore the NULL at the end
59     I64_MIN_REP_LENGTH = sizeof(I64_MIN_REP) - 1 //Ignore the NULL at the end
60 };
61 
62 U_NAMESPACE_BEGIN
63 
64 // -------------------------------------
65 // default constructor
66 
DigitList()67 DigitList::DigitList()
68 {
69     // BEGIN android-added
70     fDecimalDigits = fDecimalDigitsBuffer;
71     fBufferSize = MAX_DEC_DIGITS;
72     // END android-added
73     fDigits = fDecimalDigits + 1;   // skip the decimal
74     clear();
75 }
76 
77 // -------------------------------------
78 
~DigitList()79 DigitList::~DigitList()
80 {
81     // BEGIN android-added
82     if (fDecimalDigits != fDecimalDigitsBuffer) free(fDecimalDigits);
83     // END android-added
84 }
85 
86 // BEGIN android-added
87 // -------------------------------------
88 // capacity constructor
89 
DigitList(int capacity)90 DigitList::DigitList(int capacity)
91 {
92     fBufferSize = capacity;
93     fDecimalDigits = (char *) calloc(capacity, 1);
94     fDigits = fDecimalDigits + 1;   // skip the decimal
95     clear();
96 }
97 // END android-added
98 
99 // -------------------------------------
100 // copy constructor
101 
DigitList(const DigitList & other)102 DigitList::DigitList(const DigitList &other)
103 {
104     // BEGIN android-added
105     fDecimalDigits = fDecimalDigitsBuffer;
106     fBufferSize = MAX_DEC_DIGITS;
107     // END android-added
108     fDigits = fDecimalDigits + 1;   // skip the decimal
109     *this = other;
110 }
111 
112 // -------------------------------------
113 // assignment operator
114 
115 DigitList&
operator =(const DigitList & other)116 DigitList::operator=(const DigitList& other)
117 {
118     if (this != &other)
119     {
120         fDecimalAt = other.fDecimalAt;
121         fCount = other.fCount;
122         fIsPositive = other.fIsPositive;
123         fRoundingMode = other.fRoundingMode;
124         // BEGIN android-added
125         if (other.fDecimalDigits != other.fDecimalDigitsBuffer)
126         {
127             fBufferSize = other.fBufferSize;
128             fDecimalDigits = (char *) malloc(fBufferSize);
129             fDigits = fDecimalDigits + 1;   // skip the decimal
130         }
131         // END android-added
132         uprv_strncpy(fDigits, other.fDigits, fCount);
133     }
134     return *this;
135 }
136 
137 // -------------------------------------
138 
139 UBool
operator ==(const DigitList & that) const140 DigitList::operator==(const DigitList& that) const
141 {
142     return ((this == &that) ||
143             (fDecimalAt == that.fDecimalAt &&
144              fCount == that.fCount &&
145              fIsPositive == that.fIsPositive &&
146              fRoundingMode == that.fRoundingMode &&
147              uprv_strncmp(fDigits, that.fDigits, fCount) == 0));
148 }
149 
150 // -------------------------------------
151 // Resets the digit list; sets all the digits to zero.
152 
153 void
clear()154 DigitList::clear()
155 {
156     fDecimalAt = 0;
157     fCount = 0;
158     fIsPositive = TRUE;
159     fRoundingMode = DecimalFormat::kRoundHalfEven;
160 
161     // Don't bother initializing fDigits because fCount is 0.
162 }
163 
164 
165 
166 // -------------------------------------
167 
168 /**
169  * Formats a number into a base 10 string representation, and NULL terminates it.
170  * @param number The number to format
171  * @param outputStr The string to output to
172  * @param outputLen The maximum number of characters to put into outputStr
173  *                  (including NULL).
174  * @return the number of digits written, not including the sign.
175  */
176 static int32_t
formatBase10(int64_t number,char * outputStr,int32_t outputLen)177 formatBase10(int64_t number, char *outputStr, int32_t outputLen)
178 {
179     char buffer[MAX_DIGITS + 1];
180     int32_t bufferLen;
181     int32_t result;
182 
183     if (outputLen > MAX_DIGITS) {
184         outputLen = MAX_DIGITS;     // Ignore NULL
185     }
186     else if (outputLen < 3) {
187         return 0;                   // Not enough room
188     }
189 
190     bufferLen = outputLen;
191 
192     if (number < 0) {   // Negative numbers are slightly larger than a postive
193         buffer[bufferLen--] = (char)(-(number % 10) + kZero);
194         number /= -10;
195         *(outputStr++) = '-';
196     }
197     else {
198         *(outputStr++) = '+';    // allow +0
199     }
200     while (bufferLen >= 0 && number) {      // Output the number
201         buffer[bufferLen--] = (char)(number % 10 + kZero);
202         number /= 10;
203     }
204 
205     result = outputLen - bufferLen++;
206 
207     while (bufferLen <= outputLen) {     // Copy the number to output
208         *(outputStr++) = buffer[bufferLen++];
209     }
210     *outputStr = 0;   // NULL terminate.
211     return result;
212 }
213 
214 /**
215  * Currently, getDouble() depends on atof() to do its conversion.
216  *
217  * WARNING!!
218  * This is an extremely costly function. ~1/2 of the conversion time
219  * can be linked to this function.
220  */
221 double
getDouble()222 DigitList::getDouble() /*const*/
223 {
224     double value;
225 
226     if (fCount == 0) {
227         value = 0.0;
228     }
229     else {
230         char* end = NULL;
231         if (!gDecimal) {
232             char rep[MAX_DIGITS];
233             // For machines that decide to change the decimal on you,
234             // and try to be too smart with localization.
235             // This normally should be just a '.'.
236             sprintf(rep, "%+1.1f", 1.0);
237             gDecimal = rep[2];
238         }
239 
240         *fDecimalDigits = gDecimal;
241         *(fDigits+fCount) = 'e';    // add an e after the digits.
242         // BEGIN android-changed
243         formatBase10(fDecimalAt,
244                      fDigits + fCount + 1,  // skip the 'e'
245                      fBufferSize - fCount - 3);  // skip the 'e' and '.'
246         // END android-changed
247         value = uprv_strtod(fDecimalDigits, &end);
248     }
249 
250     return fIsPositive ? value : -value;
251 }
252 
253 // -------------------------------------
254 
255 /**
256  * Make sure that fitsIntoLong() is called before calling this function.
257  */
getLong()258 int32_t DigitList::getLong() /*const*/
259 {
260     if (fCount == fDecimalAt) {
261         int32_t value;
262 
263         fDigits[fCount] = 0;    // NULL terminate
264 
265         // This conversion is bad on 64-bit platforms when we want to
266         // be able to return a 64-bit number [grhoten]
267         *fDecimalDigits = fIsPositive ? '+' : '-';
268         value = (int32_t)atol(fDecimalDigits);
269         return value;
270     }
271     else {
272         // This is 100% accurate in c++ because if we are representing
273         // an integral value, we suffer nothing in the conversion to
274         // double.  If we are to support 64-bit longs later, getLong()
275         // must be rewritten. [LIU]
276         return (int32_t)getDouble();
277     }
278 }
279 
280 
281 /**
282  * Make sure that fitsIntoInt64() is called before calling this function.
283  */
getInt64()284 int64_t DigitList::getInt64() /*const*/
285 {
286     if (fCount == fDecimalAt) {
287         uint64_t value;
288 
289         fDigits[fCount] = 0;    // NULL terminate
290 
291         // This conversion is bad on 64-bit platforms when we want to
292         // be able to return a 64-bit number [grhoten]
293         *fDecimalDigits = fIsPositive ? '+' : '-';
294 
295         // emulate a platform independent atoi64()
296         value = 0;
297         for (int i = 0; i < fCount; ++i) {
298             int v = fDigits[i] - kZero;
299             value = value * (uint64_t)10 + (uint64_t)v;
300         }
301         if (!fIsPositive) {
302             value = ~value;
303             value += 1;
304         }
305         int64_t svalue = (int64_t)value;
306         return svalue;
307     }
308     else {
309         // TODO: figure out best approach
310 
311         // This is 100% accurate in c++ because if we are representing
312         // an integral value, we suffer nothing in the conversion to
313         // double.  If we are to support 64-bit longs later, getLong()
314         // must be rewritten. [LIU]
315         return (int64_t)getDouble();
316     }
317 }
318 
319 /**
320  * Return true if the number represented by this object can fit into
321  * a long.
322  */
323 UBool
fitsIntoLong(UBool ignoreNegativeZero)324 DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/
325 {
326     // Figure out if the result will fit in a long.  We have to
327     // first look for nonzero digits after the decimal point;
328     // then check the size.
329 
330     // Trim trailing zeros after the decimal point. This does not change
331     // the represented value.
332     while (fCount > fDecimalAt && fCount > 0 && fDigits[fCount - 1] == kZero)
333         --fCount;
334 
335     if (fCount == 0) {
336         // Positive zero fits into a long, but negative zero can only
337         // be represented as a double. - bug 4162852
338         return fIsPositive || ignoreNegativeZero;
339     }
340 
341     // If the digit list represents a double or this number is too
342     // big for a long.
343     if (fDecimalAt < fCount || fDecimalAt > LONG_MIN_REP_LENGTH)
344         return FALSE;
345 
346     // If number is small enough to fit in a long
347     if (fDecimalAt < LONG_MIN_REP_LENGTH)
348         return TRUE;
349 
350     // At this point we have fDecimalAt == fCount, and fCount == LONG_MIN_REP_LENGTH.
351     // The number will overflow if it is larger than LONG_MAX
352     // or smaller than LONG_MIN.
353     for (int32_t i=0; i<fCount; ++i)
354     {
355         char dig = fDigits[i],
356              max = LONG_MIN_REP[i];
357         if (dig > max)
358             return FALSE;
359         if (dig < max)
360             return TRUE;
361     }
362 
363     // At this point the first count digits match.  If fDecimalAt is less
364     // than count, then the remaining digits are zero, and we return true.
365     if (fCount < fDecimalAt)
366         return TRUE;
367 
368     // Now we have a representation of Long.MIN_VALUE, without the leading
369     // negative sign.  If this represents a positive value, then it does
370     // not fit; otherwise it fits.
371     return !fIsPositive;
372 }
373 
374 /**
375  * Return true if the number represented by this object can fit into
376  * a long.
377  */
378 UBool
fitsIntoInt64(UBool ignoreNegativeZero)379 DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/
380 {
381     // Figure out if the result will fit in a long.  We have to
382     // first look for nonzero digits after the decimal point;
383     // then check the size.
384 
385     // Trim trailing zeros after the decimal point. This does not change
386     // the represented value.
387     while (fCount > fDecimalAt && fCount > 0 && fDigits[fCount - 1] == kZero)
388         --fCount;
389 
390     if (fCount == 0) {
391         // Positive zero fits into a long, but negative zero can only
392         // be represented as a double. - bug 4162852
393         return fIsPositive || ignoreNegativeZero;
394     }
395 
396     // If the digit list represents a double or this number is too
397     // big for a long.
398     if (fDecimalAt < fCount || fDecimalAt > I64_MIN_REP_LENGTH)
399         return FALSE;
400 
401     // If number is small enough to fit in an int64
402     if (fDecimalAt < I64_MIN_REP_LENGTH)
403         return TRUE;
404 
405     // At this point we have fDecimalAt == fCount, and fCount == INT64_MIN_REP_LENGTH.
406     // The number will overflow if it is larger than U_INT64_MAX
407     // or smaller than U_INT64_MIN.
408     for (int32_t i=0; i<fCount; ++i)
409     {
410         char dig = fDigits[i],
411              max = I64_MIN_REP[i];
412         if (dig > max)
413             return FALSE;
414         if (dig < max)
415             return TRUE;
416     }
417 
418     // At this point the first count digits match.  If fDecimalAt is less
419     // than count, then the remaining digits are zero, and we return true.
420     if (fCount < fDecimalAt)
421         return TRUE;
422 
423     // Now we have a representation of INT64_MIN_VALUE, without the leading
424     // negative sign.  If this represents a positive value, then it does
425     // not fit; otherwise it fits.
426     return !fIsPositive;
427 }
428 
429 
430 // -------------------------------------
431 
432 void
set(int32_t source,int32_t maximumDigits)433 DigitList::set(int32_t source, int32_t maximumDigits)
434 {
435     set((int64_t)source, maximumDigits);
436 }
437 
438 // -------------------------------------
439 /**
440  * @param maximumDigits The maximum digits to be generated.  If zero,
441  * there is no maximum -- generate all digits.
442  */
443 void
set(int64_t source,int32_t maximumDigits)444 DigitList::set(int64_t source, int32_t maximumDigits)
445 {
446     fCount = fDecimalAt = formatBase10(source, fDecimalDigits, MAX_DIGITS);
447 
448     fIsPositive = (*fDecimalDigits == '+');
449 
450     // Don't copy trailing zeros
451     while (fCount > 1 && fDigits[fCount - 1] == kZero)
452         --fCount;
453 
454     if(maximumDigits > 0)
455         round(maximumDigits);
456 }
457 
458 /**
459  * Set the digit list to a representation of the given double value.
460  * This method supports both fixed-point and exponential notation.
461  * @param source Value to be converted; must not be Inf, -Inf, Nan,
462  * or a value <= 0.
463  * @param maximumDigits The most fractional or total digits which should
464  * be converted.  If total digits, and the value is zero, then
465  * there is no maximum -- generate all digits.
466  * @param fixedPoint If true, then maximumDigits is the maximum
467  * fractional digits to be converted.  If false, total digits.
468  */
469 void
set(double source,int32_t maximumDigits,UBool fixedPoint)470 DigitList::set(double source, int32_t maximumDigits, UBool fixedPoint)
471 {
472     // for now, simple implementation; later, do proper IEEE stuff
473     char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough)
474     char *digitPtr      = fDigits;
475     char *repPtr        = rep + 2;  // +2 to skip the sign and decimal
476     int32_t exponent    = 0;
477 
478     fIsPositive = !uprv_isNegative(source);    // Allow +0 and -0
479 
480     // Generate a representation of the form /[+-][0-9]+e[+-][0-9]+/
481     sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source);
482     fDecimalAt  = 0;
483     rep[2]      = rep[1];    // remove decimal
484 
485     while (*repPtr == kZero) {
486         repPtr++;
487         fDecimalAt--;   // account for leading zeros
488     }
489 
490     while (*repPtr != 'e') {
491         *(digitPtr++) = *(repPtr++);
492     }
493     fCount = MAX_DBL_DIGITS + fDecimalAt;
494 
495     // Parse an exponent of the form /[eE][+-][0-9]+/
496     UBool negExp = (*(++repPtr) == '-');
497     while (*(++repPtr) != 0) {
498         exponent = 10*exponent + *repPtr - kZero;
499     }
500     if (negExp) {
501         exponent = -exponent;
502     }
503     fDecimalAt += exponent + 1; // +1 for decimal removal
504 
505     // The negative of the exponent represents the number of leading
506     // zeros between the decimal and the first non-zero digit, for
507     // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2).  If this
508     // is more than the maximum fraction digits, then we have an underflow
509     // for the printed representation.
510     if (fixedPoint && -fDecimalAt >= maximumDigits)
511     {
512         // If we round 0.0009 to 3 fractional digits, then we have to
513         // create a new one digit in the least significant location.
514         if (-fDecimalAt == maximumDigits && shouldRoundUp(0)) {
515             fCount = 1;
516             ++fDecimalAt;
517             fDigits[0] = (char)'1';
518         } else {
519             // Handle an underflow to zero when we round something like
520             // 0.0009 to 2 fractional digits.
521             fCount = 0;
522         }
523         return;
524     }
525 
526 
527     // Eliminate digits beyond maximum digits to be displayed.
528     // Round up if appropriate.  Do NOT round in the special
529     // case where maximumDigits == 0 and fixedPoint is FALSE.
530     if (fixedPoint || (0 < maximumDigits && maximumDigits < fCount)) {
531         round(fixedPoint ? (maximumDigits + fDecimalAt) : maximumDigits);
532     }
533     else {
534         // Eliminate trailing zeros.
535         while (fCount > 1 && fDigits[fCount - 1] == kZero)
536             --fCount;
537     }
538 }
539 
540 // -------------------------------------
541 
542 /**
543  * Round the representation to the given number of digits.
544  * @param maximumDigits The maximum number of digits to be shown.
545  * Upon return, count will be less than or equal to maximumDigits.
546  */
547 void
round(int32_t maximumDigits)548 DigitList::round(int32_t maximumDigits)
549 {
550     // Eliminate digits beyond maximum digits to be displayed.
551     // Round up if appropriate.
552     if (maximumDigits >= 0 && maximumDigits < fCount)
553     {
554         if (shouldRoundUp(maximumDigits)) {
555             // Rounding up involved incrementing digits from LSD to MSD.
556             // In most cases this is simple, but in a worst case situation
557             // (9999..99) we have to adjust the decimalAt value.
558             while (--maximumDigits >= 0 && ++fDigits[maximumDigits] > '9')
559                 ;
560 
561             if (maximumDigits < 0)
562             {
563                 // We have all 9's, so we increment to a single digit
564                 // of one and adjust the exponent.
565                 fDigits[0] = (char) '1';
566                 ++fDecimalAt;
567                 maximumDigits = 1; // Adjust the count
568             }
569             else
570             {
571                 ++maximumDigits; // Increment for use as count
572             }
573         }
574         fCount = maximumDigits;
575     }
576 
577     // Eliminate trailing zeros.
578     while (fCount > 1 && fDigits[fCount-1] == kZero) {
579         --fCount;
580     }
581 }
582 
583 /**
584  * Return true if truncating the representation to the given number
585  * of digits will result in an increment to the last digit.  This
586  * method implements the requested rounding mode.
587  * [bnf]
588  * @param maximumDigits the number of digits to keep, from 0 to
589  * <code>count-1</code>.  If 0, then all digits are rounded away, and
590  * this method returns true if a one should be generated (e.g., formatting
591  * 0.09 with "#.#").
592  * @return true if digit <code>maximumDigits-1</code> should be
593  * incremented
594  */
shouldRoundUp(int32_t maximumDigits) const595 UBool DigitList::shouldRoundUp(int32_t maximumDigits) const {
596     int i = 0;
597     if (fRoundingMode == DecimalFormat::kRoundDown ||
598         fRoundingMode == DecimalFormat::kRoundFloor   &&  fIsPositive ||
599         fRoundingMode == DecimalFormat::kRoundCeiling && !fIsPositive) {
600         return FALSE;
601     }
602 
603     if (fRoundingMode == DecimalFormat::kRoundHalfEven ||
604         fRoundingMode == DecimalFormat::kRoundHalfDown ||
605         fRoundingMode == DecimalFormat::kRoundHalfUp) {
606         if (fDigits[maximumDigits] == '5' ) {
607             for (i=maximumDigits+1; i<fCount; ++i) {
608                 if (fDigits[i] != kZero) {
609                     return TRUE;
610                 }
611             }
612             switch (fRoundingMode) {
613             case DecimalFormat::kRoundHalfEven:
614             default:
615                 // Implement IEEE half-even rounding
616                 return maximumDigits > 0 && (fDigits[maximumDigits-1] % 2 != 0);
617             case DecimalFormat::kRoundHalfDown:
618                 return FALSE;
619             case DecimalFormat::kRoundHalfUp:
620                 return TRUE;
621             }
622         }
623         return (fDigits[maximumDigits] > '5');
624     }
625 
626     U_ASSERT(fRoundingMode == DecimalFormat::kRoundUp ||
627              fRoundingMode == DecimalFormat::kRoundFloor   && !fIsPositive ||
628              fRoundingMode == DecimalFormat::kRoundCeiling &&  fIsPositive);
629 
630      for (i=maximumDigits; i<fCount; ++i) {
631          if (fDigits[i] != kZero) {
632              return TRUE;
633          }
634      }
635      return false;
636 }
637 
638 // -------------------------------------
639 
640 // In the Java implementation, we need a separate set(long) because 64-bit longs
641 // have too much precision to fit into a 64-bit double.  In C++, longs can just
642 // be passed to set(double) as long as they are 32 bits in size.  We currently
643 // don't implement 64-bit longs in C++, although the code below would work for
644 // that with slight modifications. [LIU]
645 /*
646 void
647 DigitList::set(long source)
648 {
649     // handle the special case of zero using a standard exponent of 0.
650     // mathematically, the exponent can be any value.
651     if (source == 0)
652     {
653         fcount = 0;
654         fDecimalAt = 0;
655         return;
656     }
657 
658     // we don't accept negative numbers, with the exception of long_min.
659     // long_min is treated specially by being represented as long_max+1,
660     // which is actually an impossible signed long value, so there is no
661     // ambiguity.  we do this for convenience, so digitlist can easily
662     // represent the digits of a long.
663     bool islongmin = (source == long_min);
664     if (islongmin)
665     {
666         source = -(source + 1); // that is, long_max
667         islongmin = true;
668     }
669     sprintf(fdigits, "%d", source);
670 
671     // now we need to compute the exponent.  it's easy in this case; it's
672     // just the same as the count.  e.g., 0.123 * 10^3 = 123.
673     fcount = strlen(fdigits);
674     fDecimalAt = fcount;
675 
676     // here's how we represent long_max + 1.  note that we always know
677     // that the last digit of long_max will not be 9, because long_max
678     // is of the form (2^n)-1.
679     if (islongmin)
680         ++fdigits[fcount-1];
681 
682     // finally, we trim off trailing zeros.  we don't alter fDecimalAt,
683     // so this has no effect on the represented value.  we know the first
684     // digit is non-zero (see code above), so we only have to check down
685     // to fdigits[1].
686     while (fcount > 1 && fdigits[fcount-1] == kzero)
687         --fcount;
688 }
689 */
690 
691 /**
692  * Return true if this object represents the value zero.  Anything with
693  * no digits, or all zero digits, is zero, regardless of fDecimalAt.
694  */
695 UBool
isZero() const696 DigitList::isZero() const
697 {
698     for (int32_t i=0; i<fCount; ++i)
699         if (fDigits[i] != kZero)
700             return FALSE;
701     return TRUE;
702 }
703 
704 U_NAMESPACE_END
705 #endif // #if !UCONFIG_NO_FORMATTING
706 
707 //eof
708