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