1 /* 2 ****************************************************************************** 3 * 4 * Copyright (C) 1997-2015, 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 class DigitInterval; 55 56 // Export an explicit template instantiation of the MaybeStackHeaderAndArray that 57 // is used as a data member of DigitList. 58 // 59 // MSVC requires this, even though it should not be necessary. 60 // No direct access to the MaybeStackHeaderAndArray leaks out of the i18n library. 61 // 62 // Macintosh produces duplicate definition linker errors with the explicit template 63 // instantiation. 64 // 65 #if !U_PLATFORM_IS_DARWIN_BASED 66 template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>; 67 #endif 68 69 70 enum EStackMode { kOnStack }; 71 72 enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 }; 73 74 /** 75 * Digit List is actually a Decimal Floating Point number. 76 * The original implementation has been replaced by a thin wrapper onto a 77 * decimal number from the decNumber library. 78 * 79 * The original DigitList API has been retained, to minimize the impact of 80 * the change on the rest of the ICU formatting code. 81 * 82 * The change to decNumber enables support for big decimal numbers, and 83 * allows rounding computations to be done directly in decimal, avoiding 84 * extra, and inaccurate, conversions to and from doubles. 85 * 86 * Original DigitList comments: 87 * 88 * Digit List utility class. Private to DecimalFormat. Handles the transcoding 89 * between numeric values and strings of characters. Only handles 90 * non-negative numbers. The division of labor between DigitList and 91 * DecimalFormat is that DigitList handles the radix 10 representation 92 * issues; DecimalFormat handles the locale-specific issues such as 93 * positive/negative, grouping, decimal point, currency, and so on. 94 * <P> 95 * A DigitList is really a representation of a floating point value. 96 * It may be an integer value; we assume that a double has sufficient 97 * precision to represent all digits of a long. 98 * <P> 99 * The DigitList representation consists of a string of characters, 100 * which are the digits radix 10, from '0' to '9'. It also has a radix 101 * 10 exponent associated with it. The value represented by a DigitList 102 * object can be computed by mulitplying the fraction f, where 0 <= f < 1, 103 * derived by placing all the digits of the list to the right of the 104 * decimal point, by 10^exponent. 105 * 106 * -------- 107 * 108 * DigitList vs. decimalNumber: 109 * 110 * DigitList stores digits with the most significant first. 111 * decNumber stores digits with the least significant first. 112 * 113 * DigitList, decimal point is before the most significant. 114 * decNumber, decimal point is after the least signficant digit. 115 * 116 * digitList: 0.ddddd * 10 ^ exp 117 * decNumber: ddddd. * 10 ^ exp 118 * 119 * digitList exponent = decNumber exponent + digit count 120 * 121 * digitList, digits are platform invariant chars, '0' - '9' 122 * decNumber, digits are binary, one per byte, 0 - 9. 123 * 124 * (decNumber library is configurable in how digits are stored, ICU has configured 125 * it this way for convenience in replacing the old DigitList implementation.) 126 */ 127 class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy 128 public: 129 130 DigitList(); 131 ~DigitList(); 132 133 /* copy constructor 134 * @param DigitList The object to be copied. 135 * @return the newly created object. 136 */ 137 DigitList(const DigitList&); // copy constructor 138 139 /* assignment operator 140 * @param DigitList The object to be copied. 141 * @return the newly created object. 142 */ 143 DigitList& operator=(const DigitList&); // assignment operator 144 145 /** 146 * Return true if another object is semantically equal to this one. 147 * @param other The DigitList to be compared for equality 148 * @return true if another object is semantically equal to this one. 149 * return false otherwise. 150 */ 151 UBool operator==(const DigitList& other) const; 152 153 int32_t compare(const DigitList& other); 154 155 156 inline UBool operator!=(const DigitList& other) const { return !operator==(other); } 157 158 /** 159 * Clears out the digits. 160 * Use before appending them. 161 * Typically, you set a series of digits with append, then at the point 162 * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount; 163 * then go on appending digits. 164 */ 165 void clear(void); 166 167 /** 168 * Remove, by rounding, any fractional part of the decimal number, 169 * leaving an integer value. 170 */ 171 void toIntegralValue(); 172 173 /** 174 * Appends digits to the list. 175 * CAUTION: this function is not recommended for new code. 176 * In the original DigitList implementation, decimal numbers were 177 * parsed by appending them to a digit list as they were encountered. 178 * With the revamped DigitList based on decNumber, append is very 179 * inefficient, and the interaction with the exponent value is confusing. 180 * Best avoided. 181 * TODO: remove this function once all use has been replaced. 182 * TODO: describe alternative to append() 183 * @param digit The digit to be appended. 184 */ 185 void append(char digit); 186 187 /** 188 * Utility routine to get the value of the digit list 189 * Returns 0.0 if zero length. 190 * @return the value of the digit list. 191 */ 192 double getDouble(void) const; 193 194 /** 195 * Utility routine to get the value of the digit list 196 * Make sure that fitsIntoLong() is called before calling this function. 197 * Returns 0 if zero length. 198 * @return the value of the digit list, return 0 if it is zero length 199 */ 200 int32_t getLong(void) /*const*/; 201 202 /** 203 * Utility routine to get the value of the digit list 204 * Make sure that fitsIntoInt64() is called before calling this function. 205 * Returns 0 if zero length. 206 * @return the value of the digit list, return 0 if it is zero length 207 */ 208 int64_t getInt64(void) /*const*/; 209 210 /** 211 * Utility routine to get the value of the digit list as a decimal string. 212 */ 213 void getDecimal(CharString &str, UErrorCode &status); 214 215 /** 216 * Return true if the number represented by this object can fit into 217 * a long. 218 * @param ignoreNegativeZero True if negative zero is ignored. 219 * @return true if the number represented by this object can fit into 220 * a long, return false otherwise. 221 */ 222 UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/; 223 224 /** 225 * Return true if the number represented by this object can fit into 226 * an int64_t. 227 * @param ignoreNegativeZero True if negative zero is ignored. 228 * @return true if the number represented by this object can fit into 229 * a long, return false otherwise. 230 */ 231 UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/; 232 233 /** 234 * Utility routine to set the value of the digit list from a double. 235 * @param source The value to be set 236 */ 237 void set(double source); 238 239 /** 240 * Utility routine to set the value of the digit list from a long. 241 * If a non-zero maximumDigits is specified, no more than that number of 242 * significant digits will be produced. 243 * @param source The value to be set 244 */ 245 void set(int32_t source); 246 247 /** 248 * Utility routine to set the value of the digit list from an int64. 249 * If a non-zero maximumDigits is specified, no more than that number of 250 * significant digits will be produced. 251 * @param source The value to be set 252 */ 253 void set(int64_t source); 254 255 /** 256 * Utility routine to set the value of the digit list from an int64. 257 * Does not set the decnumber unless requested later 258 * If a non-zero maximumDigits is specified, no more than that number of 259 * significant digits will be produced. 260 * @param source The value to be set 261 */ 262 void setInteger(int64_t source); 263 264 /** 265 * Utility routine to set the value of the digit list from a decimal number 266 * string. 267 * @param source The value to be set. The string must be nul-terminated. 268 * @param fastpathBits special flags for fast parsing 269 */ 270 void set(const StringPiece &source, UErrorCode &status, uint32_t fastpathBits = 0); 271 272 /** 273 * Multiply this = this * arg 274 * This digitlist will be expanded if necessary to accomodate the result. 275 * @param arg the number to multiply by. 276 */ 277 void mult(const DigitList &arg, UErrorCode &status); 278 279 /** 280 * Divide this = this / arg 281 */ 282 void div(const DigitList &arg, UErrorCode &status); 283 284 // The following functions replace direct access to the original DigitList implmentation 285 // data structures. 286 287 void setRoundingMode(DecimalFormat::ERoundingMode m); 288 289 /** Test a number for zero. 290 * @return TRUE if the number is zero 291 */ 292 UBool isZero(void) const; 293 294 /** Test for a Nan 295 * @return TRUE if the number is a NaN 296 */ 297 UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);} 298 299 UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);} 300 301 /** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */ 302 void reduce(); 303 304 /** Remove trailing fraction zeros, adjust exponent accordingly. */ 305 void trim(); 306 307 /** Set to zero */ 308 void setToZero() {uprv_decNumberZero(fDecNumber);} 309 310 /** get the number of digits in the decimal number */ 311 int32_t digits() const {return fDecNumber->digits;} 312 313 /** 314 * Round the number to the given number of digits. 315 * @param maximumDigits The maximum number of digits to be shown. 316 * Upon return, count will be less than or equal to maximumDigits. 317 * result is guaranteed to be trimmed. 318 */ 319 void round(int32_t maximumDigits); 320 321 void roundFixedPoint(int32_t maximumFractionDigits); 322 323 /** Ensure capacity for digits. Grow the storage if it is currently less than 324 * the requested size. Capacity is not reduced if it is already greater 325 * than requested. 326 */ 327 void ensureCapacity(int32_t requestedSize, UErrorCode &status); 328 329 UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;} 330 void setPositive(UBool s); 331 332 void setDecimalAt(int32_t d); 333 int32_t getDecimalAt(); 334 335 void setCount(int32_t c); 336 int32_t getCount() const; 337 338 /** 339 * Set the digit in platform (invariant) format, from '0'..'9' 340 * @param i index of digit 341 * @param v digit value, from '0' to '9' in platform invariant format 342 */ 343 void setDigit(int32_t i, char v); 344 345 /** 346 * Get the digit in platform (invariant) format, from '0'..'9' inclusive 347 * @param i index of digit 348 * @return invariant format of the digit 349 */ 350 char getDigit(int32_t i); 351 352 353 /** 354 * Get the digit's value, as an integer from 0..9 inclusive. 355 * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t. 356 * @param i index of digit 357 * @return value of that digit 358 */ 359 uint8_t getDigitValue(int32_t i); 360 361 /** 362 * Gets the upper bound exponent for this value. For 987, returns 3 363 * because 10^3 is the smallest power of 10 that is just greater than 364 * 987. 365 */ 366 int32_t getUpperExponent() const; 367 368 /** 369 * Gets the lower bound exponent for this value. For 98.7, returns -1 370 * because the right most digit, is the 10^-1 place. 371 */ 372 int32_t getLowerExponent() const { return fDecNumber->exponent; } 373 374 /** 375 * Sets result to the smallest DigitInterval needed to display this 376 * DigitList in fixed point form and returns result. 377 */ 378 DigitInterval& getSmallestInterval(DigitInterval &result) const; 379 380 /** 381 * Like getDigitValue, but the digit is identified by exponent. 382 * For example, getDigitByExponent(7) returns the 10^7 place of this 383 * DigitList. Unlike getDigitValue, there are no upper or lower bounds 384 * for passed parameter. Instead, getDigitByExponent returns 0 if 385 * the exponent falls outside the interval for this DigitList. 386 */ 387 uint8_t getDigitByExponent(int32_t exponent) const; 388 389 /** 390 * Appends the digits in this object to a CharString. 391 * 3 is appended as (char) 3, not '3' 392 */ 393 void appendDigitsTo(CharString &str, UErrorCode &status) const; 394 395 /** 396 * Equivalent to roundFixedPoint(-digitExponent) except unlike 397 * roundFixedPoint, this works for any digitExponent value. 398 * If maxSigDigits is set then this instance is rounded to have no more 399 * than maxSigDigits. The end result is guaranteed to be trimmed. 400 */ 401 void roundAtExponent(int32_t digitExponent, int32_t maxSigDigits=INT32_MAX); 402 403 /** 404 * Quantizes according to some amount and rounds according to the 405 * context of this instance. Quantizing 3.233 with 0.05 gives 3.25. 406 */ 407 void quantize(const DigitList &amount, UErrorCode &status); 408 409 /** 410 * Like toScientific but only returns the exponent 411 * leaving this instance unchanged. 412 */ 413 int32_t getScientificExponent( 414 int32_t minIntDigitCount, int32_t exponentMultiplier) const; 415 416 /** 417 * Converts this instance to scientific notation. This instance 418 * becomes the mantissa and the exponent is returned. 419 * @param minIntDigitCount minimum integer digits in mantissa 420 * Exponent is set so that the actual number of integer digits 421 * in mantissa is as close to the minimum as possible. 422 * @param exponentMultiplier The exponent is always a multiple of 423 * This number. Usually 1, but set to 3 for engineering notation. 424 * @return exponent 425 */ 426 int32_t toScientific( 427 int32_t minIntDigitCount, int32_t exponentMultiplier); 428 429 /** 430 * Shifts decimal to the right. 431 */ 432 void shiftDecimalRight(int32_t numPlaces); 433 434 private: 435 /* 436 * These data members are intentionally public and can be set directly. 437 *<P> 438 * The value represented is given by placing the decimal point before 439 * fDigits[fDecimalAt]. If fDecimalAt is < 0, then leading zeros between 440 * the decimal point and the first nonzero digit are implied. If fDecimalAt 441 * is > fCount, then trailing zeros between the fDigits[fCount-1] and the 442 * decimal point are implied. 443 * <P> 444 * Equivalently, the represented value is given by f * 10^fDecimalAt. Here 445 * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to 446 * the right of the decimal. 447 * <P> 448 * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero. We 449 * don't allow denormalized numbers because our exponent is effectively of 450 * unlimited magnitude. The fCount value contains the number of significant 451 * digits present in fDigits[]. 452 * <P> 453 * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i] 454 * for all i <= fCount == '0'. 455 * 456 * int32_t fDecimalAt; 457 * int32_t fCount; 458 * UBool fIsPositive; 459 * char *fDigits; 460 * DecimalFormat::ERoundingMode fRoundingMode; 461 */ 462 463 public: 464 decContext fContext; // public access to status flags. 465 466 private: 467 decNumber *fDecNumber; 468 MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS> fStorage; 469 470 /* Cached double value corresponding to this decimal number. 471 * This is an optimization for the formatting implementation, which may 472 * ask for the double value multiple times. 473 */ 474 union DoubleOrInt64 { 475 double fDouble; 476 int64_t fInt64; 477 } fUnion; 478 enum EHave { 479 kNone=0, 480 kDouble, 481 kInt64 482 } fHave; 483 484 485 486 UBool shouldRoundUp(int32_t maximumDigits) const; 487 488 public: 489 490 #if U_OVERRIDE_CXX_ALLOCATION 491 using UMemory::operator new; 492 using UMemory::operator delete; 493 #else 494 static inline void * U_EXPORT2 operator new(size_t size) U_NO_THROW { return ::operator new(size); }; 495 static inline void U_EXPORT2 operator delete(void *ptr ) U_NO_THROW { ::operator delete(ptr); }; 496 #endif 497 static char U_EXPORT2 getStrtodDecimalSeparator(); 498 499 /** 500 * Placement new for stack usage 501 * @internal 502 */ 503 static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode /*mode*/) U_NO_THROW { return onStack; } 504 505 /** 506 * Placement delete for stack usage 507 * @internal 508 */ 509 static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/) U_NO_THROW {} 510 511 private: 512 inline void internalSetDouble(double d) { 513 fHave = kDouble; 514 fUnion.fDouble=d; 515 } 516 inline void internalSetInt64(int64_t d) { 517 fHave = kInt64; 518 fUnion.fInt64=d; 519 } 520 inline void internalClear() { 521 fHave = kNone; 522 } 523 }; 524 525 526 U_NAMESPACE_END 527 528 #endif // #if !UCONFIG_NO_FORMATTING 529 #endif // _DIGITLST 530 531 //eof 532