• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ******************************************************************************
5 *
6 *   Copyright (C) 1997-2015, International Business Machines
7 *   Corporation and others.  All Rights Reserved.
8 *
9 ******************************************************************************
10 *
11 * File DIGITLST.H
12 *
13 * Modification History:
14 *
15 *   Date        Name        Description
16 *   02/25/97    aliu        Converted from java.
17 *   03/21/97    clhuang     Updated per C++ implementation.
18 *   04/15/97    aliu        Changed MAX_COUNT to DBL_DIG.  Changed Digit to char.
19 *   09/09/97    aliu        Adapted for exponential notation support.
20 *   08/02/98    stephen     Added nearest/even rounding
21 *   06/29/99    stephen     Made LONG_DIGITS a macro to satisfy SUN compiler
22 *   07/09/99    stephen     Removed kMaxCount (unused, for HP compiler)
23 ******************************************************************************
24 */
25 
26 #ifndef DIGITLST_H
27 #define DIGITLST_H
28 
29 #include "unicode/uobject.h"
30 
31 #if !UCONFIG_NO_FORMATTING
32 #include "unicode/decimfmt.h"
33 #include <float.h>
34 #include "decContext.h"
35 #include "decNumber.h"
36 #include "cmemory.h"
37 
38 // Decimal digits in a 64-bit int
39 #define INT64_DIGITS 19
40 
41 typedef enum EDigitListValues {
42     MAX_DBL_DIGITS = DBL_DIG,
43     MAX_I64_DIGITS = INT64_DIGITS,
44     MAX_DIGITS = MAX_I64_DIGITS,
45     MAX_EXPONENT = DBL_DIG,
46     DIGIT_PADDING = 3,
47     DEFAULT_DIGITS = 40,   // Initial storage size, will grow as needed.
48 
49      // "+." + fDigits + "e" + fDecimalAt
50     MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
51 } EDigitListValues;
52 
53 U_NAMESPACE_BEGIN
54 
55 class CharString;
56 class DigitInterval;
57 
58 // Export an explicit template instantiation of the MaybeStackHeaderAndArray that
59 //    is used as a data member of DigitList.
60 //
61 //    MSVC requires this, even though it should not be necessary.
62 //    No direct access to the MaybeStackHeaderAndArray leaks out of the i18n library.
63 //
64 //    Macintosh produces duplicate definition linker errors with the explicit template
65 //    instantiation.
66 //
67 #if !U_PLATFORM_IS_DARWIN_BASED
68 template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>;
69 #endif
70 
71 
72 enum EStackMode { kOnStack };
73 
74 enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 };
75 
76 /**
77  * Digit List is actually a Decimal Floating Point number.
78  * The original implementation has been replaced by a thin wrapper onto a
79  * decimal number from the decNumber library.
80  *
81  * The original DigitList API has been retained, to minimize the impact of
82  * the change on the rest of the ICU formatting code.
83  *
84  * The change to decNumber enables support for big decimal numbers, and
85  * allows rounding computations to be done directly in decimal, avoiding
86  * extra, and inaccurate, conversions to and from doubles.
87  *
88  * Original DigitList comments:
89  *
90  * Digit List utility class. Private to DecimalFormat.  Handles the transcoding
91  * between numeric values and strings of characters.  Only handles
92  * non-negative numbers.  The division of labor between DigitList and
93  * DecimalFormat is that DigitList handles the radix 10 representation
94  * issues; DecimalFormat handles the locale-specific issues such as
95  * positive/negative, grouping, decimal point, currency, and so on.
96  * <P>
97  * A DigitList is really a representation of a floating point value.
98  * It may be an integer value; we assume that a double has sufficient
99  * precision to represent all digits of a long.
100  * <P>
101  * The DigitList representation consists of a string of characters,
102  * which are the digits radix 10, from '0' to '9'.  It also has a radix
103  * 10 exponent associated with it.  The value represented by a DigitList
104  * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
105  * derived by placing all the digits of the list to the right of the
106  * decimal point, by 10^exponent.
107  *
108  * --------
109  *
110  * DigitList vs. decimalNumber:
111  *
112  *    DigitList stores digits with the most significant first.
113  *    decNumber stores digits with the least significant first.
114  *
115  *    DigitList, decimal point is before the most significant.
116  *    decNumber, decimal point is after the least signficant digit.
117  *
118  *       digitList:    0.ddddd * 10 ^ exp
119  *       decNumber:    ddddd. * 10 ^ exp
120  *
121  *       digitList exponent = decNumber exponent + digit count
122  *
123  *    digitList, digits are platform invariant chars, '0' - '9'
124  *    decNumber, digits are binary, one per byte, 0 - 9.
125  *
126  *       (decNumber library is configurable in how digits are stored, ICU has configured
127  *        it this way for convenience in replacing the old DigitList implementation.)
128  */
129 class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy
130 public:
131 
132     DigitList();
133     ~DigitList();
134 
135     /* copy constructor
136      * @param DigitList The object to be copied.
137      * @return the newly created object.
138      */
139     DigitList(const DigitList&); // copy constructor
140 
141     /* assignment operator
142      * @param DigitList The object to be copied.
143      * @return the newly created object.
144      */
145     DigitList& operator=(const DigitList&);  // assignment operator
146 
147     /**
148      * Return true if another object is semantically equal to this one.
149      * @param other The DigitList to be compared for equality
150      * @return true if another object is semantically equal to this one.
151      * return false otherwise.
152      */
153     UBool operator==(const DigitList& other) const;
154 
155     int32_t  compare(const DigitList& other);
156 
157 
158     inline UBool operator!=(const DigitList& other) const { return !operator==(other); }
159 
160     /**
161      * Clears out the digits.
162      * Use before appending them.
163      * Typically, you set a series of digits with append, then at the point
164      * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount;
165      * then go on appending digits.
166      */
167     void clear(void);
168 
169     /**
170      *  Remove, by rounding, any fractional part of the decimal number,
171      *  leaving an integer value.
172      */
173     void toIntegralValue();
174 
175     /**
176      * Appends digits to the list.
177      *    CAUTION:  this function is not recommended for new code.
178      *              In the original DigitList implementation, decimal numbers were
179      *              parsed by appending them to a digit list as they were encountered.
180      *              With the revamped DigitList based on decNumber, append is very
181      *              inefficient, and the interaction with the exponent value is confusing.
182      *              Best avoided.
183      *              TODO:  remove this function once all use has been replaced.
184      *              TODO:  describe alternative to append()
185      * @param digit The digit to be appended.
186      */
187     void append(char digit);
188 
189     /**
190      * Utility routine to get the value of the digit list
191      * Returns 0.0 if zero length.
192      * @return the value of the digit list.
193      */
194     double getDouble(void) const;
195 
196     /**
197      * Utility routine to get the value of the digit list
198      * Make sure that fitsIntoLong() is called before calling this function.
199      * Returns 0 if zero length.
200      * @return the value of the digit list, return 0 if it is zero length
201      */
202     int32_t getLong(void) /*const*/;
203 
204     /**
205      * Utility routine to get the value of the digit list
206      * Make sure that fitsIntoInt64() is called before calling this function.
207      * Returns 0 if zero length.
208      * @return the value of the digit list, return 0 if it is zero length
209      */
210     int64_t getInt64(void) /*const*/;
211 
212     /**
213      *  Utility routine to get the value of the digit list as a decimal string.
214      */
215     void getDecimal(CharString &str, UErrorCode &status);
216 
217     /**
218      * Return true if the number represented by this object can fit into
219      * a long.
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 fitsIntoLong(UBool ignoreNegativeZero) /*const*/;
225 
226     /**
227      * Return true if the number represented by this object can fit into
228      * an int64_t.
229      * @param ignoreNegativeZero True if negative zero is ignored.
230      * @return true if the number represented by this object can fit into
231      * a long, return false otherwise.
232      */
233     UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/;
234 
235     /**
236      * Utility routine to set the value of the digit list from a double.
237      * @param source The value to be set
238      */
239     void set(double source);
240 
241     /**
242      * Utility routine to set the value of the digit list from a long.
243      * If a non-zero maximumDigits is specified, no more than that number of
244      * significant digits will be produced.
245      * @param source The value to be set
246      */
247     void set(int32_t source);
248 
249     /**
250      * Utility routine to set the value of the digit list from an int64.
251      * If a non-zero maximumDigits is specified, no more than that number of
252      * significant digits will be produced.
253      * @param source The value to be set
254      */
255     void set(int64_t source);
256 
257     /**
258      * Utility routine to set the value of the digit list from an int64.
259      * Does not set the decnumber unless requested later
260      * If a non-zero maximumDigits is specified, no more than that number of
261      * significant digits will be produced.
262      * @param source The value to be set
263      */
264     void setInteger(int64_t source);
265 
266    /**
267      * Utility routine to set the value of the digit list from a decimal number
268      * string.
269      * @param source The value to be set.  The string must be nul-terminated.
270      * @param fastpathBits special flags for fast parsing
271      */
272     void set(StringPiece source, UErrorCode &status, uint32_t fastpathBits = 0);
273 
274     /**
275      * Multiply    this = this * arg
276      *    This digitlist will be expanded if necessary to accomodate the result.
277      *  @param arg  the number to multiply by.
278      */
279     void mult(const DigitList &arg, UErrorCode &status);
280 
281     /**
282      *   Divide    this = this / arg
283      */
284     void div(const DigitList &arg, UErrorCode &status);
285 
286     //  The following functions replace direct access to the original DigitList implmentation
287     //  data structures.
288 
289     void setRoundingMode(DecimalFormat::ERoundingMode m);
290 
291     /** Test a number for zero.
292      * @return  TRUE if the number is zero
293      */
294     UBool isZero(void) const;
295 
296     /** Test for a Nan
297      * @return  TRUE if the number is a NaN
298      */
isNaN(void)299     UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}
300 
isInfinite()301     UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);}
302 
303     /**  Reduce, or normalize.  Removes trailing zeroes, adjusts exponent appropriately. */
304     void     reduce();
305 
306     /**  Remove trailing fraction zeros, adjust exponent accordingly. */
307     void     trim();
308 
309     /** Set to zero */
setToZero()310     void     setToZero() {uprv_decNumberZero(fDecNumber);}
311 
312     /** get the number of digits in the decimal number */
digits()313     int32_t  digits() const {return fDecNumber->digits;}
314 
315     /**
316      * Round the number to the given number of digits.
317      * @param maximumDigits The maximum number of digits to be shown.
318      * Upon return, count will be less than or equal to maximumDigits.
319      * result is guaranteed to be trimmed.
320      */
321     void round(int32_t maximumDigits);
322 
323     void roundFixedPoint(int32_t maximumFractionDigits);
324 
325     /** Ensure capacity for digits.  Grow the storage if it is currently less than
326      *      the requested size.   Capacity is not reduced if it is already greater
327      *      than requested.
328      */
329     void  ensureCapacity(int32_t  requestedSize, UErrorCode &status);
330 
isPositive(void)331     UBool    isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;}
332     void     setPositive(UBool s);
333 
334     void     setDecimalAt(int32_t d);
335     int32_t  getDecimalAt();
336 
337     void     setCount(int32_t c);
338     int32_t  getCount() const;
339 
340     /**
341      * Set the digit in platform (invariant) format, from '0'..'9'
342      * @param i index of digit
343      * @param v digit value, from '0' to '9' in platform invariant format
344      */
345     void     setDigit(int32_t i, char v);
346 
347     /**
348      * Get the digit in platform (invariant) format, from '0'..'9' inclusive
349      * @param i index of digit
350      * @return invariant format of the digit
351      */
352     char     getDigit(int32_t i);
353 
354 
355     /**
356      * Get the digit's value, as an integer from 0..9 inclusive.
357      * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t.
358      * @param i index of digit
359      * @return value of that digit
360      */
361     uint8_t     getDigitValue(int32_t i);
362 
363     /**
364      * Gets the upper bound exponent for this value. For 987, returns 3
365      * because 10^3 is the smallest power of 10 that is just greater than
366      * 987.
367      */
368     int32_t getUpperExponent() const;
369 
370     /**
371      * Gets the lower bound exponent for this value. For 98.7, returns -1
372      * because the right most digit, is the 10^-1 place.
373      */
getLowerExponent()374     int32_t getLowerExponent() const { return fDecNumber->exponent; }
375 
376     /**
377      * Sets result to the smallest DigitInterval needed to display this
378      * DigitList in fixed point form and returns result.
379      */
380     DigitInterval& getSmallestInterval(DigitInterval &result) const;
381 
382     /**
383      * Like getDigitValue, but the digit is identified by exponent.
384      * For example, getDigitByExponent(7) returns the 10^7 place of this
385      * DigitList. Unlike getDigitValue, there are no upper or lower bounds
386      * for passed parameter. Instead, getDigitByExponent returns 0 if
387      * the exponent falls outside the interval for this DigitList.
388      */
389     uint8_t getDigitByExponent(int32_t exponent) const;
390 
391     /**
392      * Appends the digits in this object to a CharString.
393      * 3 is appended as (char) 3, not '3'
394      */
395     void appendDigitsTo(CharString &str, UErrorCode &status) const;
396 
397     /**
398      * Equivalent to roundFixedPoint(-digitExponent) except unlike
399      * roundFixedPoint, this works for any digitExponent value.
400      * If maxSigDigits is set then this instance is rounded to have no more
401      * than maxSigDigits. The end result is guaranteed to be trimmed.
402      */
403     void roundAtExponent(int32_t digitExponent, int32_t maxSigDigits=INT32_MAX);
404 
405     /**
406      * Quantizes according to some amount and rounds according to the
407      * context of this instance. Quantizing 3.233 with 0.05 gives 3.25.
408      */
409     void quantize(const DigitList &amount, UErrorCode &status);
410 
411     /**
412      * Like toScientific but only returns the exponent
413      * leaving this instance unchanged.
414      */
415     int32_t getScientificExponent(
416             int32_t minIntDigitCount, int32_t exponentMultiplier) const;
417 
418     /**
419      * Converts this instance to scientific notation. This instance
420      * becomes the mantissa and the exponent is returned.
421      * @param minIntDigitCount minimum integer digits in mantissa
422      *   Exponent is set so that the actual number of integer digits
423      *   in mantissa is as close to the minimum as possible.
424      * @param exponentMultiplier The exponent is always a multiple of
425      *  This number. Usually 1, but set to 3 for engineering notation.
426      * @return exponent
427      */
428     int32_t toScientific(
429             int32_t minIntDigitCount, int32_t exponentMultiplier);
430 
431     /**
432      * Shifts decimal to the right.
433      */
434     void shiftDecimalRight(int32_t numPlaces);
435 
436 private:
437     /*
438      * These data members are intentionally public and can be set directly.
439      *<P>
440      * The value represented is given by placing the decimal point before
441      * fDigits[fDecimalAt].  If fDecimalAt is < 0, then leading zeros between
442      * the decimal point and the first nonzero digit are implied.  If fDecimalAt
443      * is > fCount, then trailing zeros between the fDigits[fCount-1] and the
444      * decimal point are implied.
445      * <P>
446      * Equivalently, the represented value is given by f * 10^fDecimalAt.  Here
447      * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to
448      * the right of the decimal.
449      * <P>
450      * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero.  We
451      * don't allow denormalized numbers because our exponent is effectively of
452      * unlimited magnitude.  The fCount value contains the number of significant
453      * digits present in fDigits[].
454      * <P>
455      * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i]
456      * for all i <= fCount == '0'.
457      *
458      * int32_t                         fDecimalAt;
459      * int32_t                         fCount;
460      * UBool                           fIsPositive;
461      * char                            *fDigits;
462      * DecimalFormat::ERoundingMode    fRoundingMode;
463      */
464 
465 public:
466     decContext    fContext;   // public access to status flags.
467 
468 private:
469     decNumber     *fDecNumber;
470     MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>  fStorage;
471 
472     /* Cached double value corresponding to this decimal number.
473      * This is an optimization for the formatting implementation, which may
474      * ask for the double value multiple times.
475      */
476     union DoubleOrInt64 {
477       double        fDouble;
478       int64_t       fInt64;
479     } fUnion;
480     enum EHave {
481       kNone=0,
482       kDouble
483     } fHave;
484 
485 
486 
487     UBool shouldRoundUp(int32_t maximumDigits) const;
488 
489  public:
490 
491 #if U_OVERRIDE_CXX_ALLOCATION
492     using UMemory::operator new;
493     using UMemory::operator delete;
494 #else
495     static inline void * U_EXPORT2 operator new(size_t size) U_NO_THROW { return ::operator new(size); };
496     static inline void U_EXPORT2 operator delete(void *ptr )  U_NO_THROW { ::operator delete(ptr); };
497 #endif
498 
499     static double U_EXPORT2 decimalStrToDouble(char *decstr, char **end);
500 
501     /**
502      * Placement new for stack usage
503      * @internal
504      */
new(size_t,void * onStack,EStackMode)505     static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode  /*mode*/) U_NO_THROW { return onStack; }
506 
507     /**
508      * Placement delete for stack usage
509      * @internal
510      */
delete(void *,void *,EStackMode)511     static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/)  U_NO_THROW {}
512 
513  private:
internalSetDouble(double d)514     inline void internalSetDouble(double d) {
515       fHave = kDouble;
516       fUnion.fDouble=d;
517     }
internalClear()518     inline void internalClear() {
519       fHave = kNone;
520     }
521 };
522 
523 
524 U_NAMESPACE_END
525 
526 #endif // #if !UCONFIG_NO_FORMATTING
527 #endif // _DIGITLST
528 
529 //eof
530