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