OLD | NEW |
(Empty) | |
| 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 tha
t |
| 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 lib
rary. |
| 60 // |
| 61 // Macintosh produces duplicate definition linker errors with the explicit te
mplate |
| 62 // instantiation. |
| 63 // |
| 64 #if !defined(U_DARWIN) |
| 65 template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGI
TS>; |
| 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 co
nfigured |
| 120 * it this way for convenience in replacing the old DigitList implementat
ion.) |
| 121 */ |
| 122 class U_I18N_API DigitList : public UMemory { // Declare external to make compil
er 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==(o
ther); }; |
| 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.f
Count; |
| 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 we
re |
| 172 * parsed by appending them to a digit list as they were encoun
tered. |
| 173 * With the revamped DigitList based on decNumber, append is ve
ry |
| 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 approp
riately. */ |
| 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 th
an |
| 308 * the requested size. Capacity is not reduced if it is already great
er |
| 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. W
e |
| 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 fDigit
s[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 |
OLD | NEW |