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