Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: icu46/source/i18n/digitlst.cpp

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

Powered by Google App Engine
This is Rietveld 408576698