2 ******************************************************************************
4 * Copyright (C) 1997-2012, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 ******************************************************************************
11 * Modification History:
13 * Date Name Description
14 * 02/25/97 aliu Converted from java.
15 * 03/21/97 clhuang Updated per C++ implementation.
16 * 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char.
17 * 09/09/97 aliu Adapted for exponential notation support.
18 * 08/02/98 stephen Added nearest/even rounding
19 * 06/29/99 stephen Made LONG_DIGITS a macro to satisfy SUN compiler
20 * 07/09/99 stephen Removed kMaxCount (unused, for HP compiler)
21 ******************************************************************************
27 #include "unicode/uobject.h"
29 #if !UCONFIG_NO_FORMATTING
30 #include "unicode/decimfmt.h"
32 #include "decContext.h"
33 #include "decNumber.h"
36 // Decimal digits in a 64-bit int
37 #define INT64_DIGITS 19
39 typedef enum EDigitListValues
{
40 MAX_DBL_DIGITS
= DBL_DIG
,
41 MAX_I64_DIGITS
= INT64_DIGITS
,
42 MAX_DIGITS
= MAX_I64_DIGITS
,
43 MAX_EXPONENT
= DBL_DIG
,
45 DEFAULT_DIGITS
= 40, // Initial storage size, will grow as needed.
47 // "+." + fDigits + "e" + fDecimalAt
48 MAX_DEC_DIGITS
= MAX_DIGITS
+ DIGIT_PADDING
+ MAX_EXPONENT
55 // Export an explicit template instantiation of the MaybeStackHeaderAndArray that
56 // is used as a data member of DigitList.
58 // MSVC requires this, even though it should not be necessary.
59 // No direct access to the MaybeStackHeaderAndArray leaks out of the i18n library.
61 // Macintosh produces duplicate definition linker errors with the explicit template
64 #if !U_PLATFORM_IS_DARWIN_BASED
65 template class U_I18N_API MaybeStackHeaderAndArray
<decNumber
, char, DEFAULT_DIGITS
>;
69 enum EStackMode
{ kOnStack
};
71 enum EFastpathBits
{ kFastpathOk
= 1, kNoDecimal
= 2 };
74 * Digit List is actually a Decimal Floating Point number.
75 * The original implementation has been replaced by a thin wrapper onto a
76 * decimal number from the decNumber library.
78 * The original DigitList API has been retained, to minimize the impact of
79 * the change on the rest of the ICU formatting code.
81 * The change to decNumber enables support for big decimal numbers, and
82 * allows rounding computations to be done directly in decimal, avoiding
83 * extra, and inaccurate, conversions to and from doubles.
85 * Original DigitList comments:
87 * Digit List utility class. Private to DecimalFormat. Handles the transcoding
88 * between numeric values and strings of characters. Only handles
89 * non-negative numbers. The division of labor between DigitList and
90 * DecimalFormat is that DigitList handles the radix 10 representation
91 * issues; DecimalFormat handles the locale-specific issues such as
92 * positive/negative, grouping, decimal point, currency, and so on.
94 * A DigitList is really a representation of a floating point value.
95 * It may be an integer value; we assume that a double has sufficient
96 * precision to represent all digits of a long.
98 * The DigitList representation consists of a string of characters,
99 * which are the digits radix 10, from '0' to '9'. It also has a radix
100 * 10 exponent associated with it. The value represented by a DigitList
101 * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
102 * derived by placing all the digits of the list to the right of the
103 * decimal point, by 10^exponent.
107 * DigitList vs. decimalNumber:
109 * DigitList stores digits with the most significant first.
110 * decNumber stores digits with the least significant first.
112 * DigitList, decimal point is before the most significant.
113 * decNumber, decimal point is after the least signficant digit.
115 * digitList: 0.ddddd * 10 ^ exp
116 * decNumber: ddddd. * 10 ^ exp
118 * digitList exponent = decNumber exponent + digit count
120 * digitList, digits are platform invariant chars, '0' - '9'
121 * decNumber, digits are binary, one per byte, 0 - 9.
123 * (decNumber library is configurable in how digits are stored, ICU has configured
124 * it this way for convenience in replacing the old DigitList implementation.)
126 class U_I18N_API DigitList
: public UMemory
{ // Declare external to make compiler happy
133 * @param DigitList The object to be copied.
134 * @return the newly created object.
136 DigitList(const DigitList
&); // copy constructor
138 /* assignment operator
139 * @param DigitList The object to be copied.
140 * @return the newly created object.
142 DigitList
& operator=(const DigitList
&); // assignment operator
145 * Return true if another object is semantically equal to this one.
146 * @param other The DigitList to be compared for equality
147 * @return true if another object is semantically equal to this one.
148 * return false otherwise.
150 UBool
operator==(const DigitList
& other
) const;
152 int32_t compare(const DigitList
& other
);
155 inline UBool
operator!=(const DigitList
& other
) const { return !operator==(other
); }
158 * Clears out the digits.
159 * Use before appending them.
160 * Typically, you set a series of digits with append, then at the point
161 * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount;
162 * then go on appending digits.
167 * Remove, by rounding, any fractional part of the decimal number,
168 * leaving an integer value.
170 void toIntegralValue();
173 * Appends digits to the list.
174 * CAUTION: this function is not recommended for new code.
175 * In the original DigitList implementation, decimal numbers were
176 * parsed by appending them to a digit list as they were encountered.
177 * With the revamped DigitList based on decNumber, append is very
178 * inefficient, and the interaction with the exponent value is confusing.
180 * TODO: remove this function once all use has been replaced.
181 * TODO: describe alternative to append()
182 * @param digit The digit to be appended.
184 void append(char digit
);
187 * Utility routine to get the value of the digit list
188 * Returns 0.0 if zero length.
189 * @return the value of the digit list.
191 double getDouble(void) const;
194 * Utility routine to get the value of the digit list
195 * Make sure that fitsIntoLong() is called before calling this function.
196 * Returns 0 if zero length.
197 * @return the value of the digit list, return 0 if it is zero length
199 int32_t getLong(void) /*const*/;
202 * Utility routine to get the value of the digit list
203 * Make sure that fitsIntoInt64() is called before calling this function.
204 * Returns 0 if zero length.
205 * @return the value of the digit list, return 0 if it is zero length
207 int64_t getInt64(void) /*const*/;
210 * Utility routine to get the value of the digit list as a decimal string.
212 void getDecimal(CharString
&str
, UErrorCode
&status
);
215 * Return true if the number represented by this object can fit into
217 * @param ignoreNegativeZero True if negative zero is ignored.
218 * @return true if the number represented by this object can fit into
219 * a long, return false otherwise.
221 UBool
fitsIntoLong(UBool ignoreNegativeZero
) /*const*/;
224 * Return true if the number represented by this object can fit into
226 * @param ignoreNegativeZero True if negative zero is ignored.
227 * @return true if the number represented by this object can fit into
228 * a long, return false otherwise.
230 UBool
fitsIntoInt64(UBool ignoreNegativeZero
) /*const*/;
233 * Utility routine to set the value of the digit list from a double.
234 * @param source The value to be set
236 void set(double source
);
239 * Utility routine to set the value of the digit list from a long.
240 * If a non-zero maximumDigits is specified, no more than that number of
241 * significant digits will be produced.
242 * @param source The value to be set
244 void set(int32_t source
);
247 * Utility routine to set the value of the digit list from an int64.
248 * If a non-zero maximumDigits is specified, no more than that number of
249 * significant digits will be produced.
250 * @param source The value to be set
252 void set(int64_t source
);
255 * Utility routine to set the value of the digit list from an int64.
256 * Does not set the decnumber unless requested later
257 * If a non-zero maximumDigits is specified, no more than that number of
258 * significant digits will be produced.
259 * @param source The value to be set
261 void setInteger(int64_t source
);
264 * Utility routine to set the value of the digit list from a decimal number
266 * @param source The value to be set. The string must be nul-terminated.
267 * @param fastpathBits special flags for fast parsing
269 void set(const StringPiece
&source
, UErrorCode
&status
, uint32_t fastpathBits
= 0);
272 * Multiply this = this * arg
273 * This digitlist will be expanded if necessary to accomodate the result.
274 * @param arg the number to multiply by.
276 void mult(const DigitList
&arg
, UErrorCode
&status
);
279 * Divide this = this / arg
281 void div(const DigitList
&arg
, UErrorCode
&status
);
283 // The following functions replace direct access to the original DigitList implmentation
286 void setRoundingMode(DecimalFormat::ERoundingMode m
);
288 /** Test a number for zero.
289 * @return TRUE if the number is zero
291 UBool
isZero(void) const;
294 * @return TRUE if the number is a NaN
296 UBool
isNaN(void) const {return decNumberIsNaN(fDecNumber
);}
298 UBool
isInfinite() const {return decNumberIsInfinite(fDecNumber
);}
300 /** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */
303 /** Remove trailing fraction zeros, adjust exponent accordingly. */
307 void setToZero() {uprv_decNumberZero(fDecNumber
);}
309 /** get the number of digits in the decimal number */
310 int32_t digits() const {return fDecNumber
->digits
;}
313 * Round the number to the given number of digits.
314 * @param maximumDigits The maximum number of digits to be shown.
315 * Upon return, count will be less than or equal to maximumDigits.
317 void round(int32_t maximumDigits
);
319 void roundFixedPoint(int32_t maximumFractionDigits
);
321 /** Ensure capacity for digits. Grow the storage if it is currently less than
322 * the requested size. Capacity is not reduced if it is already greater
325 void ensureCapacity(int32_t requestedSize
, UErrorCode
&status
);
327 UBool
isPositive(void) const { return decNumberIsNegative(fDecNumber
) == 0;}
328 void setPositive(UBool s
);
330 void setDecimalAt(int32_t d
);
331 int32_t getDecimalAt();
333 void setCount(int32_t c
);
334 int32_t getCount() const;
337 * Set the digit in platform (invariant) format, from '0'..'9'
338 * @param i index of digit
339 * @param v digit value, from '0' to '9' in platform invariant format
341 void setDigit(int32_t i
, char v
);
344 * Get the digit in platform (invariant) format, from '0'..'9' inclusive
345 * @param i index of digit
346 * @return invariant format of the digit
348 char getDigit(int32_t i
);
352 * Get the digit's value, as an integer from 0..9 inclusive.
353 * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t.
354 * @param i index of digit
355 * @return value of that digit
357 uint8_t getDigitValue(int32_t i
);
362 * These data members are intentionally public and can be set directly.
364 * The value represented is given by placing the decimal point before
365 * fDigits[fDecimalAt]. If fDecimalAt is < 0, then leading zeros between
366 * the decimal point and the first nonzero digit are implied. If fDecimalAt
367 * is > fCount, then trailing zeros between the fDigits[fCount-1] and the
368 * decimal point are implied.
370 * Equivalently, the represented value is given by f * 10^fDecimalAt. Here
371 * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to
372 * the right of the decimal.
374 * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero. We
375 * don't allow denormalized numbers because our exponent is effectively of
376 * unlimited magnitude. The fCount value contains the number of significant
377 * digits present in fDigits[].
379 * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i]
380 * for all i <= fCount == '0'.
382 * int32_t fDecimalAt;
386 * DecimalFormat::ERoundingMode fRoundingMode;
390 decContext fContext
; // public access to status flags.
393 decNumber
*fDecNumber
;
394 MaybeStackHeaderAndArray
<decNumber
, char, DEFAULT_DIGITS
> fStorage
;
396 /* Cached double value corresponding to this decimal number.
397 * This is an optimization for the formatting implementation, which may
398 * ask for the double value multiple times.
400 union DoubleOrInt64
{
412 UBool
shouldRoundUp(int32_t maximumDigits
) const;
416 using UMemory::operator new;
417 using UMemory::operator delete;
420 * Placement new for stack usage
423 static inline void * U_EXPORT2
operator new(size_t /*size*/, void * onStack
, EStackMode
/*mode*/) U_NO_THROW
{ return onStack
; }
426 * Placement delete for stack usage
429 static inline void U_EXPORT2
operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode
/*mode*/) U_NO_THROW
{}
432 inline void internalSetDouble(double d
) {
436 inline void internalSetInt64(int64_t d
) {
440 inline void internalClear() {
448 #endif // #if !UCONFIG_NO_FORMATTING