• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ******************************************************************************
3 *
4 *   Copyright (C) 1997-2010, International Business Machines
5 *   Corporation and others.  All Rights Reserved.
6 *
7 ******************************************************************************
8 *
9 * File DIGITLST.H
10 *
11 * Modification History:
12 *
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 ******************************************************************************
22 */
23 
24 #ifndef DIGITLST_H
25 #define DIGITLST_H
26 
27 #include "unicode/uobject.h"
28 
29 #if !UCONFIG_NO_FORMATTING
30 #include "unicode/decimfmt.h"
31 #include <float.h>
32 #include "decContext.h"
33 #include "decNumber.h"
34 #include "cmemory.h"
35 #include "decnumstr.h"
36 
37 // Decimal digits in a 64-bit int
38 #define INT64_DIGITS 19
39 
40 typedef enum EDigitListValues {
41     MAX_DBL_DIGITS = DBL_DIG,
42     MAX_I64_DIGITS = INT64_DIGITS,
43     MAX_DIGITS = MAX_I64_DIGITS,
44     MAX_EXPONENT = DBL_DIG,
45     DIGIT_PADDING = 3,
46     DEFAULT_DIGITS = 40,   // Initial storage size, will grow as needed.
47 
48      // "+." + fDigits + "e" + fDecimalAt
49     MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
50 } EDigitListValues;
51 
52 U_NAMESPACE_BEGIN
53 
54 // Export an explicit template instantiation of the MaybeStackArray that
55 //    is used as a data member of DigitList.
56 //
57 //    MSVC requires this, even though it should not be necessary.
58 //    No direct access to the MaybeStackArray leaks out of the i18n library.
59 //
60 //    Macintosh produces duplicate definition linker errors with the explicit template
61 //    instantiation.
62 //
63 #if !defined(U_DARWIN)
64 template class U_I18N_API MaybeStackArray<char, sizeof(decNumber) + DEFAULT_DIGITS>;
65 #endif
66 
67 
68 /**
69  * Digit List is actually a Decimal Floating Point number.
70  * The original implementation has been replaced by a thin wrapper onto a
71  * decimal number from the decNumber library.
72  *
73  * The original DigitList API has been retained, to minimize the impact of
74  * the change on the rest of the ICU formatting code.
75  *
76  * The change to decNumber enables support for big decimal numbers, and
77  * allows rounding computations to be done directly in decimal, avoiding
78  * extra, and inaccurate, conversions to and from doubles.
79  *
80  * Original DigitList comments:
81  *
82  * Digit List utility class. Private to DecimalFormat.  Handles the transcoding
83  * between numeric values and strings of characters.  Only handles
84  * non-negative numbers.  The division of labor between DigitList and
85  * DecimalFormat is that DigitList handles the radix 10 representation
86  * issues; DecimalFormat handles the locale-specific issues such as
87  * positive/negative, grouping, decimal point, currency, and so on.
88  * <P>
89  * A DigitList is really a representation of a floating point value.
90  * It may be an integer value; we assume that a double has sufficient
91  * precision to represent all digits of a long.
92  * <P>
93  * The DigitList representation consists of a string of characters,
94  * which are the digits radix 10, from '0' to '9'.  It also has a radix
95  * 10 exponent associated with it.  The value represented by a DigitList
96  * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
97  * derived by placing all the digits of the list to the right of the
98  * decimal point, by 10^exponent.
99  *
100  * --------
101  *
102  * DigitList vs. decimalNumber:
103  *
104  *    DigitList stores digits with the most significant first.
105  *    decNumber stores digits with the least significant first.
106  *
107  *    DigitList, decimal point is before the most significant.
108  *    decNumber, decimal point is after the least signficant digit.
109  *
110  *       digitList:    0.ddddd * 10 ^ exp
111  *       decNumber:    ddddd. * 10 ^ exp
112  *
113  *       digitList exponent = decNumber exponent + digit count
114  *
115  *    digitList, digits are chars, '0' - '9'
116  *    decNumber, digits are binary, one per byte, 0 - 9.
117  *
118  *       (decNumber library is configurable in how digits are stored, ICU has configured
119  *        it this way for convenience in replacing the old DigitList implementation.)
120  */
121 class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy
122 public:
123 
124     DigitList();
125     ~DigitList();
126 
127     /* copy constructor
128      * @param DigitList The object to be copied.
129      * @return the newly created object.
130      */
131     DigitList(const DigitList&); // copy constructor
132 
133     /* assignment operator
134      * @param DigitList The object to be copied.
135      * @return the newly created object.
136      */
137     DigitList& operator=(const DigitList&);  // assignment operator
138 
139     /**
140      * Return true if another object is semantically equal to this one.
141      * @param other The DigitList to be compared for equality
142      * @return true if another object is semantically equal to this one.
143      * return false otherwise.
144      */
145     UBool operator==(const DigitList& other) const;
146 
147     int32_t  compare(const DigitList& other);
148 
149 
150     inline UBool operator!=(const DigitList& other) const { return !operator==(other); };
151 
152     /**
153      * Clears out the digits.
154      * Use before appending them.
155      * Typically, you set a series of digits with append, then at the point
156      * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount;
157      * then go on appending digits.
158      */
159     void clear(void);
160 
161     /**
162      *  Remove, by rounding, any fractional part of the decimal number,
163      *  leaving an integer value.
164      */
165     void toIntegralValue();
166 
167     /**
168      * Appends digits to the list.
169      *    CAUTION:  this function is not recommended for new code.
170      *              In the original DigitList implementation, decimal numbers were
171      *              parsed by appending them to a digit list as they were encountered.
172      *              With the revamped DigitList based on decNumber, append is very
173      *              inefficient, and the interaction with the exponent value is confusing.
174      *              Best avoided.
175      *              TODO:  remove this function once all use has been replaced.
176      * @param digit The digit to be appended.
177      */
178     void append(char digit);
179 
180     /**
181      * Utility routine to get the value of the digit list
182      * Returns 0.0 if zero length.
183      * @return the value of the digit list.
184      */
185     double getDouble(void) const;
186 
187     /**
188      * Utility routine to get the value of the digit list
189      * Make sure that fitsIntoLong() is called before calling this function.
190      * Returns 0 if zero length.
191      * @return the value of the digit list, return 0 if it is zero length
192      */
193     int32_t getLong(void) /*const*/;
194 
195     /**
196      * Utility routine to get the value of the digit list
197      * Make sure that fitsIntoInt64() is called before calling this function.
198      * Returns 0 if zero length.
199      * @return the value of the digit list, return 0 if it is zero length
200      */
201     int64_t getInt64(void) /*const*/;
202 
203     /**
204      *  Utility routine to get the value of the digit list as a decimal string.
205      */
206     void getDecimal(DecimalNumberString &str, UErrorCode &status);
207 
208     /**
209      * Return true if the number represented by this object can fit into
210      * a long.
211      * @param ignoreNegativeZero True if negative zero is ignored.
212      * @return true if the number represented by this object can fit into
213      * a long, return false otherwise.
214      */
215     UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/;
216 
217     /**
218      * Return true if the number represented by this object can fit into
219      * an int64_t.
220      * @param ignoreNegativeZero True if negative zero is ignored.
221      * @return true if the number represented by this object can fit into
222      * a long, return false otherwise.
223      */
224     UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/;
225 
226     /**
227      * Utility routine to set the value of the digit list from a double.
228      * @param source The value to be set
229      */
230     void set(double source);
231 
232     /**
233      * Utility routine to set the value of the digit list from a long.
234      * If a non-zero maximumDigits is specified, no more than that number of
235      * significant digits will be produced.
236      * @param source The value to be set
237      */
238     void set(int32_t source);
239 
240     /**
241      * Utility routine to set the value of the digit list from an int64.
242      * If a non-zero maximumDigits is specified, no more than that number of
243      * significant digits will be produced.
244      * @param source The value to be set
245      */
246     void set(int64_t source);
247 
248    /**
249      * Utility routine to set the value of the digit list from a decimal number
250      * string.
251      * @param source The value to be set.  The string must be nul-terminated.
252      */
253     void set(const StringPiece &source, UErrorCode &status);
254 
255     /**
256      * Multiply    this = this * arg
257      *    This digitlist will be expanded if necessary to accomodate the result.
258      *  @param arg  the number to multiply by.
259      */
260     void mult(const DigitList &arg, UErrorCode &status);
261 
262     /**
263      *   Divide    this = this / arg
264      */
265     void div(const DigitList &arg, UErrorCode &status);
266 
267     //  The following functions replace direct access to the original DigitList implmentation
268     //  data structures.
269 
270     void setRoundingMode(DecimalFormat::ERoundingMode m);
271 
272     /** Test a number for zero.
273      * @return  TRUE if the number is zero
274      */
275     UBool isZero(void) const;
276 
277     /** Test for a Nan
278      * @return  TRUE if the number is a NaN
279      */
isNaN(void)280     UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);};
281 
isInfinite()282     UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);};
283 
284     /**  Reduce, or normalize.  Removes trailing zeroes, adjusts exponent appropriately. */
285     void     reduce();
286 
287     /**  Remove trailing fraction zeros, adjust exponent accordingly. */
288     void     trim();
289 
290     /** Set to zero */
setToZero()291     void     setToZero() {uprv_decNumberZero(fDecNumber);};
292 
293     /** get the number of digits in the decimal number */
digits()294     int32_t  digits() const {return fDecNumber->digits;};
295 
296     /**
297      * Round the number to the given number of digits.
298      * @param maximumDigits The maximum number of digits to be shown.
299      * Upon return, count will be less than or equal to maximumDigits.
300      */
301     void round(int32_t maximumDigits);
302 
303     void roundFixedPoint(int32_t maximumFractionDigits);
304 
305     /** Ensure capacity for digits.  Grow the storage if it is currently less than
306      *      the requested size.   Capacity is not reduced if it is already greater
307      *      than requested.
308      */
309     void  ensureCapacity(int32_t  requestedSize, UErrorCode &status);
310 
isPositive(void)311     UBool    isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;};
312     void     setPositive(UBool s);
313 
314     void     setDecimalAt(int32_t d);
315     int32_t  getDecimalAt();
316 
317     void     setCount(int32_t c);
318     int32_t  getCount() const;
319 
320     void     setDigit(int32_t i, char v);
321     char     getDigit(int32_t i);
322 
323 
324 private:
325     /*
326      * These data members are intentionally public and can be set directly.
327      *<P>
328      * The value represented is given by placing the decimal point before
329      * fDigits[fDecimalAt].  If fDecimalAt is < 0, then leading zeros between
330      * the decimal point and the first nonzero digit are implied.  If fDecimalAt
331      * is > fCount, then trailing zeros between the fDigits[fCount-1] and the
332      * decimal point are implied.
333      * <P>
334      * Equivalently, the represented value is given by f * 10^fDecimalAt.  Here
335      * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to
336      * the right of the decimal.
337      * <P>
338      * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero.  We
339      * don't allow denormalized numbers because our exponent is effectively of
340      * unlimited magnitude.  The fCount value contains the number of significant
341      * digits present in fDigits[].
342      * <P>
343      * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i]
344      * for all i <= fCount == '0'.
345      *
346      * int32_t                         fDecimalAt;
347      * int32_t                         fCount;
348      * UBool                           fIsPositive;
349      * char                            *fDigits;
350      * DecimalFormat::ERoundingMode    fRoundingMode;
351      */
352 
353 private:
354 
355     decContext    fContext;
356     decNumber     *fDecNumber;
357     MaybeStackArray<char, sizeof(decNumber) + DEFAULT_DIGITS>  fStorage;
358 
359     /* Cached double value corresponding to this decimal number.
360      * This is an optimization for the formatting implementation, which may
361      * ask for the double value multiple times.
362      */
363     double        fDouble;
364     UBool         fHaveDouble;
365 
366 
367 
368     UBool shouldRoundUp(int32_t maximumDigits) const;
369 };
370 
371 
372 U_NAMESPACE_END
373 
374 #endif // #if !UCONFIG_NO_FORMATTING
375 #endif // _DIGITLST
376 
377 //eof
378