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