Home | History | Annotate | Download | only in i18n
      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      */
    282     UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);};
    283 
    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 */
    293     void     setToZero() {uprv_decNumberZero(fDecNumber);};
    294 
    295     /** get the number of digits in the decimal number */
    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 
    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