Home | History | Annotate | Download | only in i18n
      1 //  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      */
    299     UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}
    300 
    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 */
    310     void     setToZero() {uprv_decNumberZero(fDecNumber);}
    311 
    312     /** get the number of digits in the decimal number */
    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 
    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      */
    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      */
    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      */
    511     static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/)  U_NO_THROW {}
    512 
    513  private:
    514     inline void internalSetDouble(double d) {
    515       fHave = kDouble;
    516       fUnion.fDouble=d;
    517     }
    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