• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ******************************************************************************
3 *
4 *   Copyright (C) 1997-2012, 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 !U_PLATFORM_IS_DARWIN_BASED
65 template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>;
66 #endif
67 
68 
69 enum EStackMode { kOnStack };
70 
71 enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 };
72 
73 /**
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.
77  *
78  * The original DigitList API has been retained, to minimize the impact of
79  * the change on the rest of the ICU formatting code.
80  *
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.
84  *
85  * Original DigitList comments:
86  *
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.
93  * <P>
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.
97  * <P>
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.
104  *
105  * --------
106  *
107  * DigitList vs. decimalNumber:
108  *
109  *    DigitList stores digits with the most significant first.
110  *    decNumber stores digits with the least significant first.
111  *
112  *    DigitList, decimal point is before the most significant.
113  *    decNumber, decimal point is after the least signficant digit.
114  *
115  *       digitList:    0.ddddd * 10 ^ exp
116  *       decNumber:    ddddd. * 10 ^ exp
117  *
118  *       digitList exponent = decNumber exponent + digit count
119  *
120  *    digitList, digits are platform invariant chars, '0' - '9'
121  *    decNumber, digits are binary, one per byte, 0 - 9.
122  *
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.)
125  */
126 class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy
127 public:
128 
129     DigitList();
130     ~DigitList();
131 
132     /* copy constructor
133      * @param DigitList The object to be copied.
134      * @return the newly created object.
135      */
136     DigitList(const DigitList&); // copy constructor
137 
138     /* assignment operator
139      * @param DigitList The object to be copied.
140      * @return the newly created object.
141      */
142     DigitList& operator=(const DigitList&);  // assignment operator
143 
144     /**
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.
149      */
150     UBool operator==(const DigitList& other) const;
151 
152     int32_t  compare(const DigitList& other);
153 
154 
155     inline UBool operator!=(const DigitList& other) const { return !operator==(other); }
156 
157     /**
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.
163      */
164     void clear(void);
165 
166     /**
167      *  Remove, by rounding, any fractional part of the decimal number,
168      *  leaving an integer value.
169      */
170     void toIntegralValue();
171 
172     /**
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.
179      *              Best avoided.
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.
183      */
184     void append(char digit);
185 
186     /**
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.
190      */
191     double getDouble(void) const;
192 
193     /**
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
198      */
199     int32_t getLong(void) /*const*/;
200 
201     /**
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
206      */
207     int64_t getInt64(void) /*const*/;
208 
209     /**
210      *  Utility routine to get the value of the digit list as a decimal string.
211      */
212     void getDecimal(CharString &str, UErrorCode &status);
213 
214     /**
215      * Return true if the number represented by this object can fit into
216      * a long.
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.
220      */
221     UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/;
222 
223     /**
224      * Return true if the number represented by this object can fit into
225      * an int64_t.
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.
229      */
230     UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/;
231 
232     /**
233      * Utility routine to set the value of the digit list from a double.
234      * @param source The value to be set
235      */
236     void set(double source);
237 
238     /**
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
243      */
244     void set(int32_t source);
245 
246     /**
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
251      */
252     void set(int64_t source);
253 
254     /**
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
260      */
261     void setInteger(int64_t source);
262 
263    /**
264      * Utility routine to set the value of the digit list from a decimal number
265      * string.
266      * @param source The value to be set.  The string must be nul-terminated.
267      * @param fastpathBits special flags for fast parsing
268      */
269     void set(const StringPiece &source, UErrorCode &status, uint32_t fastpathBits = 0);
270 
271     /**
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.
275      */
276     void mult(const DigitList &arg, UErrorCode &status);
277 
278     /**
279      *   Divide    this = this / arg
280      */
281     void div(const DigitList &arg, UErrorCode &status);
282 
283     //  The following functions replace direct access to the original DigitList implmentation
284     //  data structures.
285 
286     void setRoundingMode(DecimalFormat::ERoundingMode m);
287 
288     /** Test a number for zero.
289      * @return  TRUE if the number is zero
290      */
291     UBool isZero(void) const;
292 
293     /** Test for a Nan
294      * @return  TRUE if the number is a NaN
295      */
isNaN(void)296     UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}
297 
isInfinite()298     UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);}
299 
300     /**  Reduce, or normalize.  Removes trailing zeroes, adjusts exponent appropriately. */
301     void     reduce();
302 
303     /**  Remove trailing fraction zeros, adjust exponent accordingly. */
304     void     trim();
305 
306     /** Set to zero */
setToZero()307     void     setToZero() {uprv_decNumberZero(fDecNumber);}
308 
309     /** get the number of digits in the decimal number */
digits()310     int32_t  digits() const {return fDecNumber->digits;}
311 
312     /**
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.
316      */
317     void round(int32_t maximumDigits);
318 
319     void roundFixedPoint(int32_t maximumFractionDigits);
320 
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
323      *      than requested.
324      */
325     void  ensureCapacity(int32_t  requestedSize, UErrorCode &status);
326 
isPositive(void)327     UBool    isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;}
328     void     setPositive(UBool s);
329 
330     void     setDecimalAt(int32_t d);
331     int32_t  getDecimalAt();
332 
333     void     setCount(int32_t c);
334     int32_t  getCount() const;
335 
336     /**
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
340      */
341     void     setDigit(int32_t i, char v);
342 
343     /**
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
347      */
348     char     getDigit(int32_t i);
349 
350 
351     /**
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
356      */
357     uint8_t     getDigitValue(int32_t i);
358 
359 
360 private:
361     /*
362      * These data members are intentionally public and can be set directly.
363      *<P>
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.
369      * <P>
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.
373      * <P>
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[].
378      * <P>
379      * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i]
380      * for all i <= fCount == '0'.
381      *
382      * int32_t                         fDecimalAt;
383      * int32_t                         fCount;
384      * UBool                           fIsPositive;
385      * char                            *fDigits;
386      * DecimalFormat::ERoundingMode    fRoundingMode;
387      */
388 
389 public:
390     decContext    fContext;   // public access to status flags.
391 
392 private:
393     decNumber     *fDecNumber;
394     MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>  fStorage;
395 
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.
399      */
400     union DoubleOrInt64 {
401       double        fDouble;
402       int64_t       fInt64;
403     } fUnion;
404     enum EHave {
405       kNone=0,
406       kDouble,
407       kInt64
408     } fHave;
409 
410 
411 
412     UBool shouldRoundUp(int32_t maximumDigits) const;
413 
414  public:
415 
416     using UMemory::operator new;
417     using UMemory::operator delete;
418 
419     /**
420      * Placement new for stack usage
421      * @internal
422      */
new(size_t,void * onStack,EStackMode)423     static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode  /*mode*/) U_NO_THROW { return onStack; }
424 
425     /**
426      * Placement delete for stack usage
427      * @internal
428      */
delete(void *,void *,EStackMode)429     static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/)  U_NO_THROW {}
430 
431  private:
internalSetDouble(double d)432     inline void internalSetDouble(double d) {
433       fHave = kDouble;
434       fUnion.fDouble=d;
435     }
internalSetInt64(int64_t d)436     inline void internalSetInt64(int64_t d) {
437       fHave = kInt64;
438       fUnion.fInt64=d;
439     }
internalClear()440     inline void internalClear() {
441       fHave = kNone;
442     }
443 };
444 
445 
446 U_NAMESPACE_END
447 
448 #endif // #if !UCONFIG_NO_FORMATTING
449 #endif // _DIGITLST
450 
451 //eof
452