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 #include "decnumstr.h" 36 37 // Decimal digits in a 64-bit int 38 #define INT64_DIGITS 19 39 40 typedef enum EDigitListValues { 41 MAX_DBL_DIGITS = DBL_DIG, 42 MAX_I64_DIGITS = INT64_DIGITS, 43 MAX_DIGITS = MAX_I64_DIGITS, 44 MAX_EXPONENT = DBL_DIG, 45 DIGIT_PADDING = 3, 46 DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed. 47 48 // "+." + fDigits + "e" + fDecimalAt 49 MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT 50 } EDigitListValues; 51 52 U_NAMESPACE_BEGIN 53 54 // Export an explicit template instantiation of the MaybeStackArray that 55 // is used as a data member of DigitList. 56 // 57 // MSVC requires this, even though it should not be necessary. 58 // No direct access to the MaybeStackArray leaks out of the i18n library. 59 // 60 // Macintosh produces duplicate definition linker errors with the explicit template 61 // instantiation. 62 // 63 #if !defined(U_DARWIN) 64 template class U_I18N_API MaybeStackArray<char, sizeof(decNumber) + DEFAULT_DIGITS>; 65 #endif 66 67 68 /** 69 * Digit List is actually a Decimal Floating Point number. 70 * The original implementation has been replaced by a thin wrapper onto a 71 * decimal number from the decNumber library. 72 * 73 * The original DigitList API has been retained, to minimize the impact of 74 * the change on the rest of the ICU formatting code. 75 * 76 * The change to decNumber enables support for big decimal numbers, and 77 * allows rounding computations to be done directly in decimal, avoiding 78 * extra, and inaccurate, conversions to and from doubles. 79 * 80 * Original DigitList comments: 81 * 82 * Digit List utility class. Private to DecimalFormat. Handles the transcoding 83 * between numeric values and strings of characters. Only handles 84 * non-negative numbers. The division of labor between DigitList and 85 * DecimalFormat is that DigitList handles the radix 10 representation 86 * issues; DecimalFormat handles the locale-specific issues such as 87 * positive/negative, grouping, decimal point, currency, and so on. 88 * <P> 89 * A DigitList is really a representation of a floating point value. 90 * It may be an integer value; we assume that a double has sufficient 91 * precision to represent all digits of a long. 92 * <P> 93 * The DigitList representation consists of a string of characters, 94 * which are the digits radix 10, from '0' to '9'. It also has a radix 95 * 10 exponent associated with it. The value represented by a DigitList 96 * object can be computed by mulitplying the fraction f, where 0 <= f < 1, 97 * derived by placing all the digits of the list to the right of the 98 * decimal point, by 10^exponent. 99 * 100 * -------- 101 * 102 * DigitList vs. decimalNumber: 103 * 104 * DigitList stores digits with the most significant first. 105 * decNumber stores digits with the least significant first. 106 * 107 * DigitList, decimal point is before the most significant. 108 * decNumber, decimal point is after the least signficant digit. 109 * 110 * digitList: 0.ddddd * 10 ^ exp 111 * decNumber: ddddd. * 10 ^ exp 112 * 113 * digitList exponent = decNumber exponent + digit count 114 * 115 * digitList, digits are chars, '0' - '9' 116 * decNumber, digits are binary, one per byte, 0 - 9. 117 * 118 * (decNumber library is configurable in how digits are stored, ICU has configured 119 * it this way for convenience in replacing the old DigitList implementation.) 120 */ 121 class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy 122 public: 123 124 DigitList(); 125 ~DigitList(); 126 127 /* copy constructor 128 * @param DigitList The object to be copied. 129 * @return the newly created object. 130 */ 131 DigitList(const DigitList&); // copy constructor 132 133 /* assignment operator 134 * @param DigitList The object to be copied. 135 * @return the newly created object. 136 */ 137 DigitList& operator=(const DigitList&); // assignment operator 138 139 /** 140 * Return true if another object is semantically equal to this one. 141 * @param other The DigitList to be compared for equality 142 * @return true if another object is semantically equal to this one. 143 * return false otherwise. 144 */ 145 UBool operator==(const DigitList& other) const; 146 147 int32_t compare(const DigitList& other); 148 149 150 inline UBool operator!=(const DigitList& other) const { return !operator==(other); }; 151 152 /** 153 * Clears out the digits. 154 * Use before appending them. 155 * Typically, you set a series of digits with append, then at the point 156 * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount; 157 * then go on appending digits. 158 */ 159 void clear(void); 160 161 /** 162 * Remove, by rounding, any fractional part of the decimal number, 163 * leaving an integer value. 164 */ 165 void toIntegralValue(); 166 167 /** 168 * Appends digits to the list. 169 * CAUTION: this function is not recommended for new code. 170 * In the original DigitList implementation, decimal numbers were 171 * parsed by appending them to a digit list as they were encountered. 172 * With the revamped DigitList based on decNumber, append is very 173 * inefficient, and the interaction with the exponent value is confusing. 174 * Best avoided. 175 * TODO: remove this function once all use has been replaced. 176 * @param digit The digit to be appended. 177 */ 178 void append(char digit); 179 180 /** 181 * Utility routine to get the value of the digit list 182 * Returns 0.0 if zero length. 183 * @return the value of the digit list. 184 */ 185 double getDouble(void) const; 186 187 /** 188 * Utility routine to get the value of the digit list 189 * Make sure that fitsIntoLong() is called before calling this function. 190 * Returns 0 if zero length. 191 * @return the value of the digit list, return 0 if it is zero length 192 */ 193 int32_t getLong(void) /*const*/; 194 195 /** 196 * Utility routine to get the value of the digit list 197 * Make sure that fitsIntoInt64() is called before calling this function. 198 * Returns 0 if zero length. 199 * @return the value of the digit list, return 0 if it is zero length 200 */ 201 int64_t getInt64(void) /*const*/; 202 203 /** 204 * Utility routine to get the value of the digit list as a decimal string. 205 */ 206 void getDecimal(DecimalNumberString &str, UErrorCode &status); 207 208 /** 209 * Return true if the number represented by this object can fit into 210 * a long. 211 * @param ignoreNegativeZero True if negative zero is ignored. 212 * @return true if the number represented by this object can fit into 213 * a long, return false otherwise. 214 */ 215 UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/; 216 217 /** 218 * Return true if the number represented by this object can fit into 219 * an int64_t. 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 fitsIntoInt64(UBool ignoreNegativeZero) /*const*/; 225 226 /** 227 * Utility routine to set the value of the digit list from a double. 228 * @param source The value to be set 229 */ 230 void set(double source); 231 232 /** 233 * Utility routine to set the value of the digit list from a long. 234 * If a non-zero maximumDigits is specified, no more than that number of 235 * significant digits will be produced. 236 * @param source The value to be set 237 */ 238 void set(int32_t source); 239 240 /** 241 * Utility routine to set the value of the digit list from an int64. 242 * If a non-zero maximumDigits is specified, no more than that number of 243 * significant digits will be produced. 244 * @param source The value to be set 245 */ 246 void set(int64_t source); 247 248 /** 249 * Utility routine to set the value of the digit list from a decimal number 250 * string. 251 * @param source The value to be set. The string must be nul-terminated. 252 */ 253 void set(const StringPiece &source, UErrorCode &status); 254 255 /** 256 * Multiply this = this * arg 257 * This digitlist will be expanded if necessary to accomodate the result. 258 * @param arg the number to multiply by. 259 */ 260 void mult(const DigitList &arg, UErrorCode &status); 261 262 /** 263 * Divide this = this / arg 264 */ 265 void div(const DigitList &arg, UErrorCode &status); 266 267 // The following functions replace direct access to the original DigitList implmentation 268 // data structures. 269 270 void setRoundingMode(DecimalFormat::ERoundingMode m); 271 272 /** Test a number for zero. 273 * @return TRUE if the number is zero 274 */ 275 UBool isZero(void) const; 276 277 /** Test for a Nan 278 * @return TRUE if the number is a NaN 279 */ isNaN(void)280 UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}; 281 isInfinite()282 UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);}; 283 284 /** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */ 285 void reduce(); 286 287 /** Remove trailing fraction zeros, adjust exponent accordingly. */ 288 void trim(); 289 290 /** Set to zero */ setToZero()291 void setToZero() {uprv_decNumberZero(fDecNumber);}; 292 293 /** get the number of digits in the decimal number */ digits()294 int32_t digits() const {return fDecNumber->digits;}; 295 296 /** 297 * Round the number to the given number of digits. 298 * @param maximumDigits The maximum number of digits to be shown. 299 * Upon return, count will be less than or equal to maximumDigits. 300 */ 301 void round(int32_t maximumDigits); 302 303 void roundFixedPoint(int32_t maximumFractionDigits); 304 305 /** Ensure capacity for digits. Grow the storage if it is currently less than 306 * the requested size. Capacity is not reduced if it is already greater 307 * than requested. 308 */ 309 void ensureCapacity(int32_t requestedSize, UErrorCode &status); 310 isPositive(void)311 UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;}; 312 void setPositive(UBool s); 313 314 void setDecimalAt(int32_t d); 315 int32_t getDecimalAt(); 316 317 void setCount(int32_t c); 318 int32_t getCount() const; 319 320 void setDigit(int32_t i, char v); 321 char getDigit(int32_t i); 322 323 324 private: 325 /* 326 * These data members are intentionally public and can be set directly. 327 *<P> 328 * The value represented is given by placing the decimal point before 329 * fDigits[fDecimalAt]. If fDecimalAt is < 0, then leading zeros between 330 * the decimal point and the first nonzero digit are implied. If fDecimalAt 331 * is > fCount, then trailing zeros between the fDigits[fCount-1] and the 332 * decimal point are implied. 333 * <P> 334 * Equivalently, the represented value is given by f * 10^fDecimalAt. Here 335 * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to 336 * the right of the decimal. 337 * <P> 338 * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero. We 339 * don't allow denormalized numbers because our exponent is effectively of 340 * unlimited magnitude. The fCount value contains the number of significant 341 * digits present in fDigits[]. 342 * <P> 343 * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i] 344 * for all i <= fCount == '0'. 345 * 346 * int32_t fDecimalAt; 347 * int32_t fCount; 348 * UBool fIsPositive; 349 * char *fDigits; 350 * DecimalFormat::ERoundingMode fRoundingMode; 351 */ 352 353 private: 354 355 decContext fContext; 356 decNumber *fDecNumber; 357 MaybeStackArray<char, sizeof(decNumber) + DEFAULT_DIGITS> fStorage; 358 359 /* Cached double value corresponding to this decimal number. 360 * This is an optimization for the formatting implementation, which may 361 * ask for the double value multiple times. 362 */ 363 double fDouble; 364 UBool fHaveDouble; 365 366 367 368 UBool shouldRoundUp(int32_t maximumDigits) const; 369 }; 370 371 372 U_NAMESPACE_END 373 374 #endif // #if !UCONFIG_NO_FORMATTING 375 #endif // _DIGITLST 376 377 //eof 378