2
**********************************************************************
3
* Copyright (C) 1997-2001, International Business Machines
4
* Corporation and others. All Rights Reserved.
5
**********************************************************************
9
* Modification History:
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
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
******************************************************************************
32
#include "unicode/putil.h"
34
// ***************************************************************************
36
// This class handles the transcoding between numeric values and strings of
37
// characters. Only handles as non-negative numbers.
38
// ***************************************************************************
41
* This is the zero digit. Array elements fDigits[i] have values from
42
* kZero to kZero + 9. Typically, this is '0'.
46
static char gDecimal = 0;
48
/* Only for 32 bit numbers. Ignore the negative sign. */
49
static const char LONG_MIN_REP[] = "2147483648";
52
LONG_MIN_REP_LENGTH = sizeof(LONG_MIN_REP) - 1 //Ignore the NULL at the end
57
// -------------------------------------
58
// default constructor
60
DigitList::DigitList()
65
// -------------------------------------
67
DigitList::~DigitList()
71
// -------------------------------------
74
DigitList::DigitList(const DigitList &other)
76
fDigits = fDecimalDigits + 1; // skip the decimal
80
// -------------------------------------
81
// assignment operator
84
DigitList::operator=(const DigitList& other)
88
fDecimalAt = other.fDecimalAt;
89
fCount = other.fCount;
90
fIsPositive = other.fIsPositive;
91
strncpy(fDigits, other.fDigits, MAX_DIGITS);
96
// -------------------------------------
99
DigitList::operator==(const DigitList& that) const
101
return ((this == &that) ||
102
(fDecimalAt == that.fDecimalAt &&
103
fCount == that.fCount &&
104
fIsPositive == that.fIsPositive &&
105
strncmp(fDigits, that.fDigits, fCount) == 0));
108
// -------------------------------------
109
// Resets the digit list; sets all the digits to zero.
114
fDigits = fDecimalDigits + 1; // skip the decimal
119
// Don't bother initializing fDigits because fCount is 0.
124
// -------------------------------------
127
* Formats a number into a base 10 string representation, and NULL terminates it.
128
* @param number The number to format
129
* @param outputStr The string to output to
130
* @param outputLen The maximum number of characters to put into outputStr
132
* @return the number of digits written, not including the sign.
135
formatBase10(int32_t number, char *outputStr, int32_t outputLen)
137
char buffer[MAX_DIGITS + 1];
140
if (outputLen > MAX_DIGITS) {
141
outputLen = MAX_DIGITS; // Ignore NULL
143
else if (outputLen < 3) {
144
return 0; // Not enough room
147
bufferLen = outputLen;
149
if (number < 0) { // Negative numbers are slightly larger than a postive
150
buffer[bufferLen--] = (char)(-(number % 10) + kZero);
152
*(outputStr++) = '-';
155
*(outputStr++) = '+'; // allow +0
157
while (bufferLen >= 0 && number) { // Output the number
158
buffer[bufferLen--] = (char)(number % 10 + kZero);
162
outputLen -= bufferLen++;
164
while (bufferLen <= MAX_DIGITS) { // Copy the number to output
165
*(outputStr++) = buffer[bufferLen++];
167
*outputStr = 0; // NULL terminate.
172
* Currently, getDouble() depends on atof() to do its conversion.
175
* This is an extremely costly function. ~1/2 of the conversion time
176
* can be linked to this function.
179
DigitList::getDouble()
188
char rep[MAX_DIGITS];
189
// For machines that decide to change the decimal on you,
190
// and try to be too smart with localization.
191
// This normally should be just a '.'.
192
sprintf(rep, "%+1.1f", 1.0);
196
*fDecimalDigits = gDecimal;
197
*(fDigits+fCount) = 'e'; // add an e after the digits.
198
formatBase10(fDecimalAt,
199
fDigits + fCount + 1, // skip the 'e'
200
MAX_DEC_DIGITS - fCount - 3); // skip the 'e' and '.'
201
value = atof(fDecimalDigits);
204
return fIsPositive ? value : -value;
207
// -------------------------------------
210
* Make sure that fitsIntoLong() is called before calling this function.
212
int32_t DigitList::getLong()
214
if (fCount == fDecimalAt) {
217
fDigits[fCount] = 0; // NULL terminate
219
// This conversion is bad on 64-bit platforms when we want to
220
// be able to return a 64-bit number [grhoten]
221
*fDecimalDigits = fIsPositive ? '+' : '-';
222
value = (int32_t)atol(fDecimalDigits);
226
// This is 100% accurate in c++ because if we are representing
227
// an integral value, we suffer nothing in the conversion to
228
// double. If we are to support 64-bit longs later, getLong()
229
// must be rewritten. [LIU]
230
return (int32_t)getDouble();
235
* Return true if the number represented by this object can fit into
239
DigitList::fitsIntoLong(UBool ignoreNegativeZero)
241
// Figure out if the result will fit in a long. We have to
242
// first look for nonzero digits after the decimal point;
243
// then check the size. If the digit count is 18 or less, then
244
// the value can definitely be represented as a long. If it is 19
245
// then it may be too large.
247
// Trim trailing zeros after the decimal point. This does not change
248
// the represented value.
249
while (fCount > fDecimalAt && fCount > 0 && fDigits[fCount - 1] == kZero)
253
// Positive zero fits into a long, but negative zero can only
254
// be represented as a double. - bug 4162852
255
return fIsPositive || ignoreNegativeZero;
258
// initializeLONG_MIN_REP();
260
// If the digit list represents a double or this number is too
262
if (fDecimalAt < fCount || fDecimalAt > LONG_MIN_REP_LENGTH)
265
// If number is small enough to fit in a long
266
if (fDecimalAt < LONG_MIN_REP_LENGTH)
269
// At this point we have fDecimalAt == fCount, and fCount == LONG_MIN_REP_LENGTH.
270
// The number will overflow if it is larger than LONG_MAX
271
// or smaller than LONG_MIN.
272
for (int32_t i=0; i<fCount; ++i)
274
char dig = fDigits[i],
275
max = LONG_MIN_REP[i];
282
// At this point the first count digits match. If fDecimalAt is less
283
// than count, then the remaining digits are zero, and we return true.
284
if (fCount < fDecimalAt)
287
// Now we have a representation of Long.MIN_VALUE, without the leading
288
// negative sign. If this represents a positive value, then it does
289
// not fit; otherwise it fits.
293
// -------------------------------------
296
* @param maximumDigits The maximum digits to be generated. If zero,
297
* there is no maximum -- generate all digits.
300
DigitList::set(int32_t source, int32_t maximumDigits)
302
fCount = fDecimalAt = formatBase10(source, fDecimalDigits, MAX_DIGITS);
304
fIsPositive = (*fDecimalDigits == '+');
306
// Don't copy trailing zeros
307
while (fCount > 1 && fDigits[fCount - 1] == kZero)
310
if(maximumDigits > 0)
311
round(maximumDigits);
315
* Set the digit list to a representation of the given double value.
316
* This method supports both fixed-point and exponential notation.
317
* @param source Value to be converted; must not be Inf, -Inf, Nan,
319
* @param maximumDigits The most fractional or total digits which should
320
* be converted. If total digits, and the value is zero, then
321
* there is no maximum -- generate all digits.
322
* @param fixedPoint If true, then maximumDigits is the maximum
323
* fractional digits to be converted. If false, total digits.
326
DigitList::set(double source, int32_t maximumDigits, UBool fixedPoint)
328
// for now, simple implementation; later, do proper IEEE stuff
329
char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough)
330
char *digitPtr = fDigits;
331
char *repPtr = rep + 2; // +2 to skip the sign and decimal
332
int32_t exponent = 0;
334
fIsPositive = !uprv_isNegative(source); // Allow +0 and -0
336
// Generate a representation of the form /[+-][0-9]+e[+-][0-9]+/
337
sprintf(rep, "%+1.*e", MAX_DIGITS - 1, source);
339
rep[2] = rep[1]; // remove decimal
341
while (*repPtr == kZero) {
343
fDecimalAt--; // account for leading zeros
346
while (*repPtr != 'e') {
347
*(digitPtr++) = *(repPtr++);
349
fCount = MAX_DIGITS + fDecimalAt;
351
// Parse an exponent of the form /[eE][+-][0-9]+/
352
UBool negExp = (*(++repPtr) == '-');
353
while (*(++repPtr) != 0) {
354
exponent = 10*exponent + *repPtr - kZero;
357
exponent = -exponent;
359
fDecimalAt += exponent + 1; // +1 for decimal removal
361
// The negative of the exponent represents the number of leading
362
// zeros between the decimal and the first non-zero digit, for
363
// a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
364
// is more than the maximum fraction digits, then we have an underflow
365
// for the printed representation.
366
if (fixedPoint && -fDecimalAt >= maximumDigits)
368
// If we round 0.0009 to 3 fractional digits, then we have to
369
// create a new one digit in the least significant location.
370
if (-fDecimalAt == maximumDigits && shouldRoundUp(0)) {
373
fDigits[0] = (char)'1';
375
// Handle an underflow to zero when we round something like
376
// 0.0009 to 2 fractional digits.
383
// Eliminate digits beyond maximum digits to be displayed.
384
// Round up if appropriate. Do NOT round in the special
385
// case where maximumDigits == 0 and fixedPoint is FALSE.
386
if (fixedPoint || (0 < maximumDigits && maximumDigits < fCount)) {
387
round(fixedPoint ? (maximumDigits + fDecimalAt) : maximumDigits);
390
// Eliminate trailing zeros.
391
while (fCount > 1 && fDigits[fCount - 1] == kZero)
396
// -------------------------------------
399
* Round the representation to the given number of digits.
400
* @param maximumDigits The maximum number of digits to be shown.
401
* Upon return, count will be less than or equal to maximumDigits.
404
DigitList::round(int32_t maximumDigits)
406
// Eliminate digits beyond maximum digits to be displayed.
407
// Round up if appropriate.
408
if (maximumDigits >= 0 && maximumDigits < fCount)
410
if (shouldRoundUp(maximumDigits)) {
411
// Rounding up involved incrementing digits from LSD to MSD.
412
// In most cases this is simple, but in a worst case situation
413
// (9999..99) we have to adjust the decimalAt value.
414
while (--maximumDigits >= 0 && ++fDigits[maximumDigits] > '9')
417
if (maximumDigits < 0)
419
// We have all 9's, so we increment to a single digit
420
// of one and adjust the exponent.
421
fDigits[0] = (char) '1';
423
maximumDigits = 1; // Adjust the count
427
++maximumDigits; // Increment for use as count
430
fCount = maximumDigits;
433
// Eliminate trailing zeros.
434
while (fCount > 1 && fDigits[fCount-1] == kZero) {
440
* Return true if truncating the representation to the given number
441
* of digits will result in an increment to the last digit. This
442
* method implements half-even rounding, the default rounding mode.
444
* @param maximumDigits the number of digits to keep, from 0 to
445
* <code>count-1</code>. If 0, then all digits are rounded away, and
446
* this method returns true if a one should be generated (e.g., formatting
448
* @return true if digit <code>maximumDigits-1</code> should be
451
UBool DigitList::shouldRoundUp(int32_t maximumDigits) {
452
// Implement IEEE half-even rounding
453
if (fDigits[maximumDigits] == '5' ) {
454
for (int i=maximumDigits+1; i<fCount; ++i) {
455
if (fDigits[i] != kZero) {
459
return maximumDigits > 0 && (fDigits[maximumDigits-1] % 2 != 0);
461
return (fDigits[maximumDigits] > '5');
464
// -------------------------------------
466
// In the Java implementation, we need a separate set(long) because 64-bit longs
467
// have too much precision to fit into a 64-bit double. In C++, longs can just
468
// be passed to set(double) as long as they are 32 bits in size. We currently
469
// don't implement 64-bit longs in C++, although the code below would work for
470
// that with slight modifications. [LIU]
473
DigitList::set(long source)
475
// handle the special case of zero using a standard exponent of 0.
476
// mathematically, the exponent can be any value.
484
// we don't accept negative numbers, with the exception of long_min.
485
// long_min is treated specially by being represented as long_max+1,
486
// which is actually an impossible signed long value, so there is no
487
// ambiguity. we do this for convenience, so digitlist can easily
488
// represent the digits of a long.
489
bool islongmin = (source == long_min);
492
source = -(source + 1); // that is, long_max
495
sprintf(fdigits, "%d", source);
497
// now we need to compute the exponent. it's easy in this case; it's
498
// just the same as the count. e.g., 0.123 * 10^3 = 123.
499
fcount = strlen(fdigits);
502
// here's how we represent long_max + 1. note that we always know
503
// that the last digit of long_max will not be 9, because long_max
504
// is of the form (2^n)-1.
508
// finally, we trim off trailing zeros. we don't alter fDecimalAt,
509
// so this has no effect on the represented value. we know the first
510
// digit is non-zero (see code above), so we only have to check down
512
while (fcount > 1 && fdigits[fcount-1] == kzero)
518
* Return true if this object represents the value zero. Anything with
519
* no digits, or all zero digits, is zero, regardless of fDecimalAt.
522
DigitList::isZero() const
524
for (int32_t i=0; i<fCount; ++i)
525
if (fDigits[i] != kZero)
531
* We represent LONG_MIN internally as LONG_MAX + 1. This is actually an impossible
532
* value, for positive long integers, so we are safe in doing so.
534
/* // This code is unused.
536
DigitList::isLONG_MIN() const
538
// initializeLONG_MIN_REP();
540
if (fCount != LONG_MIN_REP_LENGTH)
543
for (int32_t i = 0; i < LONG_MIN_REP_LENGTH; ++i)
545
if (fDigits[i] != LONG_MIN_REP[i+1])
553
// Initialize the LONG_MIN representation buffer. Note that LONG_MIN
554
// is stored as LONG_MAX+1 (LONG_MIN without the negative sign).
557
DigitList::initializeLONG_MIN_REP()
559
if (LONG_MIN_REP_LENGTH == 0)
561
char buf[LONG_DIGITS];
562
sprintf(buf, "%d", INT32_MIN);
563
LONG_MIN_REP_LENGTH = strlen(buf) - 1;
564
// assert(LONG_MIN_REP_LENGTH == LONG_DIGITS);
565
for (int32_t i=1; i<=LONG_MIN_REP_LENGTH; ++i)
566
LONG_MIN_REP[i-1] = buf[i];