]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/digitlst.h
ICU-57132.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / digitlst.h
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 } fHave;
482
483
484
485 UBool shouldRoundUp(int32_t maximumDigits) const;
486
487 public:
488
489 #if U_OVERRIDE_CXX_ALLOCATION
490 using UMemory::operator new;
491 using UMemory::operator delete;
492 #else
493 static inline void * U_EXPORT2 operator new(size_t size) U_NO_THROW { return ::operator new(size); };
494 static inline void U_EXPORT2 operator delete(void *ptr ) U_NO_THROW { ::operator delete(ptr); };
495 #endif
496 static char U_EXPORT2 getStrtodDecimalSeparator();
497
498 /**
499 * Placement new for stack usage
500 * @internal
501 */
502 static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode /*mode*/) U_NO_THROW { return onStack; }
503
504 /**
505 * Placement delete for stack usage
506 * @internal
507 */
508 static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/) U_NO_THROW {}
509
510 private:
511 inline void internalSetDouble(double d) {
512 fHave = kDouble;
513 fUnion.fDouble=d;
514 }
515 inline void internalClear() {
516 fHave = kNone;
517 }
518 };
519
520
521 U_NAMESPACE_END
522
523 #endif // #if !UCONFIG_NO_FORMATTING
524 #endif // _DIGITLST
525
526 //eof