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