| /* |
| ****************************************************************************** |
| * |
| * Copyright (C) 1997-2012, International Business Machines |
| * Corporation and others. All Rights Reserved. |
| * |
| ****************************************************************************** |
| * |
| * File DIGITLST.H |
| * |
| * Modification History: |
| * |
| * Date Name Description |
| * 02/25/97 aliu Converted from java. |
| * 03/21/97 clhuang Updated per C++ implementation. |
| * 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char. |
| * 09/09/97 aliu Adapted for exponential notation support. |
| * 08/02/98 stephen Added nearest/even rounding |
| * 06/29/99 stephen Made LONG_DIGITS a macro to satisfy SUN compiler |
| * 07/09/99 stephen Removed kMaxCount (unused, for HP compiler) |
| ****************************************************************************** |
| */ |
| |
| #ifndef DIGITLST_H |
| #define DIGITLST_H |
| |
| #include "unicode/uobject.h" |
| |
| #if !UCONFIG_NO_FORMATTING |
| #include "unicode/decimfmt.h" |
| #include <float.h> |
| #include "decContext.h" |
| #include "decNumber.h" |
| #include "cmemory.h" |
| |
| // Decimal digits in a 64-bit int |
| #define INT64_DIGITS 19 |
| |
| typedef enum EDigitListValues { |
| MAX_DBL_DIGITS = DBL_DIG, |
| MAX_I64_DIGITS = INT64_DIGITS, |
| MAX_DIGITS = MAX_I64_DIGITS, |
| MAX_EXPONENT = DBL_DIG, |
| DIGIT_PADDING = 3, |
| DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed. |
| |
| // "+." + fDigits + "e" + fDecimalAt |
| MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT |
| } EDigitListValues; |
| |
| U_NAMESPACE_BEGIN |
| |
| class CharString; |
| |
| // Export an explicit template instantiation of the MaybeStackHeaderAndArray that |
| // is used as a data member of DigitList. |
| // |
| // MSVC requires this, even though it should not be necessary. |
| // No direct access to the MaybeStackHeaderAndArray leaks out of the i18n library. |
| // |
| // Macintosh produces duplicate definition linker errors with the explicit template |
| // instantiation. |
| // |
| #if !U_PLATFORM_IS_DARWIN_BASED |
| template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>; |
| #endif |
| |
| |
| enum EStackMode { kOnStack }; |
| |
| enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 }; |
| |
| /** |
| * Digit List is actually a Decimal Floating Point number. |
| * The original implementation has been replaced by a thin wrapper onto a |
| * decimal number from the decNumber library. |
| * |
| * The original DigitList API has been retained, to minimize the impact of |
| * the change on the rest of the ICU formatting code. |
| * |
| * The change to decNumber enables support for big decimal numbers, and |
| * allows rounding computations to be done directly in decimal, avoiding |
| * extra, and inaccurate, conversions to and from doubles. |
| * |
| * Original DigitList comments: |
| * |
| * Digit List utility class. Private to DecimalFormat. Handles the transcoding |
| * between numeric values and strings of characters. Only handles |
| * non-negative numbers. The division of labor between DigitList and |
| * DecimalFormat is that DigitList handles the radix 10 representation |
| * issues; DecimalFormat handles the locale-specific issues such as |
| * positive/negative, grouping, decimal point, currency, and so on. |
| * <P> |
| * A DigitList is really a representation of a floating point value. |
| * It may be an integer value; we assume that a double has sufficient |
| * precision to represent all digits of a long. |
| * <P> |
| * The DigitList representation consists of a string of characters, |
| * which are the digits radix 10, from '0' to '9'. It also has a radix |
| * 10 exponent associated with it. The value represented by a DigitList |
| * object can be computed by mulitplying the fraction f, where 0 <= f < 1, |
| * derived by placing all the digits of the list to the right of the |
| * decimal point, by 10^exponent. |
| * |
| * -------- |
| * |
| * DigitList vs. decimalNumber: |
| * |
| * DigitList stores digits with the most significant first. |
| * decNumber stores digits with the least significant first. |
| * |
| * DigitList, decimal point is before the most significant. |
| * decNumber, decimal point is after the least signficant digit. |
| * |
| * digitList: 0.ddddd * 10 ^ exp |
| * decNumber: ddddd. * 10 ^ exp |
| * |
| * digitList exponent = decNumber exponent + digit count |
| * |
| * digitList, digits are platform invariant chars, '0' - '9' |
| * decNumber, digits are binary, one per byte, 0 - 9. |
| * |
| * (decNumber library is configurable in how digits are stored, ICU has configured |
| * it this way for convenience in replacing the old DigitList implementation.) |
| */ |
| class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy |
| public: |
| |
| DigitList(); |
| ~DigitList(); |
| |
| /* copy constructor |
| * @param DigitList The object to be copied. |
| * @return the newly created object. |
| */ |
| DigitList(const DigitList&); // copy constructor |
| |
| /* assignment operator |
| * @param DigitList The object to be copied. |
| * @return the newly created object. |
| */ |
| DigitList& operator=(const DigitList&); // assignment operator |
| |
| /** |
| * Return true if another object is semantically equal to this one. |
| * @param other The DigitList to be compared for equality |
| * @return true if another object is semantically equal to this one. |
| * return false otherwise. |
| */ |
| UBool operator==(const DigitList& other) const; |
| |
| int32_t compare(const DigitList& other); |
| |
| |
| inline UBool operator!=(const DigitList& other) const { return !operator==(other); } |
| |
| /** |
| * Clears out the digits. |
| * Use before appending them. |
| * Typically, you set a series of digits with append, then at the point |
| * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount; |
| * then go on appending digits. |
| */ |
| void clear(void); |
| |
| /** |
| * Remove, by rounding, any fractional part of the decimal number, |
| * leaving an integer value. |
| */ |
| void toIntegralValue(); |
| |
| /** |
| * Appends digits to the list. |
| * CAUTION: this function is not recommended for new code. |
| * In the original DigitList implementation, decimal numbers were |
| * parsed by appending them to a digit list as they were encountered. |
| * With the revamped DigitList based on decNumber, append is very |
| * inefficient, and the interaction with the exponent value is confusing. |
| * Best avoided. |
| * TODO: remove this function once all use has been replaced. |
| * TODO: describe alternative to append() |
| * @param digit The digit to be appended. |
| */ |
| void append(char digit); |
| |
| /** |
| * Utility routine to get the value of the digit list |
| * Returns 0.0 if zero length. |
| * @return the value of the digit list. |
| */ |
| double getDouble(void) const; |
| |
| /** |
| * Utility routine to get the value of the digit list |
| * Make sure that fitsIntoLong() is called before calling this function. |
| * Returns 0 if zero length. |
| * @return the value of the digit list, return 0 if it is zero length |
| */ |
| int32_t getLong(void) /*const*/; |
| |
| /** |
| * Utility routine to get the value of the digit list |
| * Make sure that fitsIntoInt64() is called before calling this function. |
| * Returns 0 if zero length. |
| * @return the value of the digit list, return 0 if it is zero length |
| */ |
| int64_t getInt64(void) /*const*/; |
| |
| /** |
| * Utility routine to get the value of the digit list as a decimal string. |
| */ |
| void getDecimal(CharString &str, UErrorCode &status); |
| |
| /** |
| * Return true if the number represented by this object can fit into |
| * a long. |
| * @param ignoreNegativeZero True if negative zero is ignored. |
| * @return true if the number represented by this object can fit into |
| * a long, return false otherwise. |
| */ |
| UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/; |
| |
| /** |
| * Return true if the number represented by this object can fit into |
| * an int64_t. |
| * @param ignoreNegativeZero True if negative zero is ignored. |
| * @return true if the number represented by this object can fit into |
| * a long, return false otherwise. |
| */ |
| UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/; |
| |
| /** |
| * Utility routine to set the value of the digit list from a double. |
| * @param source The value to be set |
| */ |
| void set(double source); |
| |
| /** |
| * Utility routine to set the value of the digit list from a long. |
| * If a non-zero maximumDigits is specified, no more than that number of |
| * significant digits will be produced. |
| * @param source The value to be set |
| */ |
| void set(int32_t source); |
| |
| /** |
| * Utility routine to set the value of the digit list from an int64. |
| * If a non-zero maximumDigits is specified, no more than that number of |
| * significant digits will be produced. |
| * @param source The value to be set |
| */ |
| void set(int64_t source); |
| |
| /** |
| * Utility routine to set the value of the digit list from an int64. |
| * Does not set the decnumber unless requested later |
| * If a non-zero maximumDigits is specified, no more than that number of |
| * significant digits will be produced. |
| * @param source The value to be set |
| */ |
| void setInteger(int64_t source); |
| |
| /** |
| * Utility routine to set the value of the digit list from a decimal number |
| * string. |
| * @param source The value to be set. The string must be nul-terminated. |
| * @param fastpathBits special flags for fast parsing |
| */ |
| void set(const StringPiece &source, UErrorCode &status, uint32_t fastpathBits = 0); |
| |
| /** |
| * Multiply this = this * arg |
| * This digitlist will be expanded if necessary to accomodate the result. |
| * @param arg the number to multiply by. |
| */ |
| void mult(const DigitList &arg, UErrorCode &status); |
| |
| /** |
| * Divide this = this / arg |
| */ |
| void div(const DigitList &arg, UErrorCode &status); |
| |
| // The following functions replace direct access to the original DigitList implmentation |
| // data structures. |
| |
| void setRoundingMode(DecimalFormat::ERoundingMode m); |
| |
| /** Test a number for zero. |
| * @return TRUE if the number is zero |
| */ |
| UBool isZero(void) const; |
| |
| /** Test for a Nan |
| * @return TRUE if the number is a NaN |
| */ |
| UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);} |
| |
| UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);} |
| |
| /** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */ |
| void reduce(); |
| |
| /** Remove trailing fraction zeros, adjust exponent accordingly. */ |
| void trim(); |
| |
| /** Set to zero */ |
| void setToZero() {uprv_decNumberZero(fDecNumber);} |
| |
| /** get the number of digits in the decimal number */ |
| int32_t digits() const {return fDecNumber->digits;} |
| |
| /** |
| * Round the number to the given number of digits. |
| * @param maximumDigits The maximum number of digits to be shown. |
| * Upon return, count will be less than or equal to maximumDigits. |
| */ |
| void round(int32_t maximumDigits); |
| |
| void roundFixedPoint(int32_t maximumFractionDigits); |
| |
| /** Ensure capacity for digits. Grow the storage if it is currently less than |
| * the requested size. Capacity is not reduced if it is already greater |
| * than requested. |
| */ |
| void ensureCapacity(int32_t requestedSize, UErrorCode &status); |
| |
| UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;} |
| void setPositive(UBool s); |
| |
| void setDecimalAt(int32_t d); |
| int32_t getDecimalAt(); |
| |
| void setCount(int32_t c); |
| int32_t getCount() const; |
| |
| /** |
| * Set the digit in platform (invariant) format, from '0'..'9' |
| * @param i index of digit |
| * @param v digit value, from '0' to '9' in platform invariant format |
| */ |
| void setDigit(int32_t i, char v); |
| |
| /** |
| * Get the digit in platform (invariant) format, from '0'..'9' inclusive |
| * @param i index of digit |
| * @return invariant format of the digit |
| */ |
| char getDigit(int32_t i); |
| |
| |
| /** |
| * Get the digit's value, as an integer from 0..9 inclusive. |
| * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t. |
| * @param i index of digit |
| * @return value of that digit |
| */ |
| uint8_t getDigitValue(int32_t i); |
| |
| |
| private: |
| /* |
| * These data members are intentionally public and can be set directly. |
| *<P> |
| * The value represented is given by placing the decimal point before |
| * fDigits[fDecimalAt]. If fDecimalAt is < 0, then leading zeros between |
| * the decimal point and the first nonzero digit are implied. If fDecimalAt |
| * is > fCount, then trailing zeros between the fDigits[fCount-1] and the |
| * decimal point are implied. |
| * <P> |
| * Equivalently, the represented value is given by f * 10^fDecimalAt. Here |
| * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to |
| * the right of the decimal. |
| * <P> |
| * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero. We |
| * don't allow denormalized numbers because our exponent is effectively of |
| * unlimited magnitude. The fCount value contains the number of significant |
| * digits present in fDigits[]. |
| * <P> |
| * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i] |
| * for all i <= fCount == '0'. |
| * |
| * int32_t fDecimalAt; |
| * int32_t fCount; |
| * UBool fIsPositive; |
| * char *fDigits; |
| * DecimalFormat::ERoundingMode fRoundingMode; |
| */ |
| |
| public: |
| decContext fContext; // public access to status flags. |
| |
| private: |
| decNumber *fDecNumber; |
| MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS> fStorage; |
| |
| /* Cached double value corresponding to this decimal number. |
| * This is an optimization for the formatting implementation, which may |
| * ask for the double value multiple times. |
| */ |
| union DoubleOrInt64 { |
| double fDouble; |
| int64_t fInt64; |
| } fUnion; |
| enum EHave { |
| kNone=0, |
| kDouble, |
| kInt64 |
| } fHave; |
| |
| |
| |
| UBool shouldRoundUp(int32_t maximumDigits) const; |
| |
| public: |
| |
| using UMemory::operator new; |
| using UMemory::operator delete; |
| |
| /** |
| * Placement new for stack usage |
| * @internal |
| */ |
| static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode /*mode*/) U_NO_THROW { return onStack; } |
| |
| /** |
| * Placement delete for stack usage |
| * @internal |
| */ |
| static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/) U_NO_THROW {} |
| |
| private: |
| inline void internalSetDouble(double d) { |
| fHave = kDouble; |
| fUnion.fDouble=d; |
| } |
| inline void internalSetInt64(int64_t d) { |
| fHave = kInt64; |
| fUnion.fInt64=d; |
| } |
| inline void internalClear() { |
| fHave = kNone; |
| } |
| }; |
| |
| |
| U_NAMESPACE_END |
| |
| #endif // #if !UCONFIG_NO_FORMATTING |
| #endif // _DIGITLST |
| |
| //eof |