Home | History | Annotate | Download | only in i18n
      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      */
    296     UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}
    297 
    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 */
    307     void     setToZero() {uprv_decNumberZero(fDecNumber);}
    308 
    309     /** get the number of digits in the decimal number */
    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 
    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      */
    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      */
    429     static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/)  U_NO_THROW {}
    430 
    431  private:
    432     inline void internalSetDouble(double d) {
    433       fHave = kDouble;
    434       fUnion.fDouble=d;
    435     }
    436     inline void internalSetInt64(int64_t d) {
    437       fHave = kInt64;
    438       fUnion.fInt64=d;
    439     }
    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