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