]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/digitlst.h
ICU-59180.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / digitlst.h
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
b75a7d8f
A
3/*
4******************************************************************************
5*
2ca993e8 6* Copyright (C) 1997-2015, International Business Machines
b75a7d8f
A
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
b75a7d8f 29#include "unicode/uobject.h"
46f4442e
A
30
31#if !UCONFIG_NO_FORMATTING
03115e54 32#include "unicode/decimfmt.h"
b75a7d8f 33#include <float.h>
729e4ab9
A
34#include "decContext.h"
35#include "decNumber.h"
36#include "cmemory.h"
b75a7d8f 37
374ca955 38// Decimal digits in a 64-bit int
374ca955 39#define INT64_DIGITS 19
b75a7d8f
A
40
41typedef enum EDigitListValues {
374ca955
A
42 MAX_DBL_DIGITS = DBL_DIG,
43 MAX_I64_DIGITS = INT64_DIGITS,
44 MAX_DIGITS = MAX_I64_DIGITS,
b75a7d8f
A
45 MAX_EXPONENT = DBL_DIG,
46 DIGIT_PADDING = 3,
729e4ab9 47 DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed.
b75a7d8f
A
48
49 // "+." + fDigits + "e" + fDecimalAt
374ca955 50 MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
b75a7d8f
A
51} EDigitListValues;
52
53U_NAMESPACE_BEGIN
54
729e4ab9 55class CharString;
2ca993e8 56class DigitInterval;
729e4ab9
A
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//
4388f060 67#if !U_PLATFORM_IS_DARWIN_BASED
729e4ab9
A
68template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>;
69#endif
70
71
51004dcb
A
72enum EStackMode { kOnStack };
73
74enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 };
75
b75a7d8f 76/**
729e4ab9
A
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 *
b75a7d8f
A
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.
729e4ab9
A
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.)
b75a7d8f 128 */
729e4ab9 129class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy
b75a7d8f 130public:
729e4ab9 131
b75a7d8f
A
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
729e4ab9
A
155 int32_t compare(const DigitList& other);
156
157
4388f060 158 inline UBool operator!=(const DigitList& other) const { return !operator==(other); }
b75a7d8f
A
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 /**
729e4ab9
A
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()
b75a7d8f
A
185 * @param digit The digit to be appended.
186 */
729e4ab9 187 void append(char digit);
b75a7d8f
A
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 */
729e4ab9 194 double getDouble(void) const;
b75a7d8f
A
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 */
374ca955
A
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*/;
b75a7d8f 211
729e4ab9
A
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
b75a7d8f
A
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 */
374ca955
A
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*/;
b75a7d8f
A
234
235 /**
729e4ab9 236 * Utility routine to set the value of the digit list from a double.
b75a7d8f 237 * @param source The value to be set
b75a7d8f 238 */
729e4ab9 239 void set(double source);
b75a7d8f
A
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
b75a7d8f 246 */
729e4ab9 247 void set(int32_t source);
b75a7d8f 248
374ca955
A
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
374ca955 254 */
729e4ab9
A
255 void set(int64_t source);
256
51004dcb
A
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
729e4ab9
A
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.
51004dcb 270 * @param fastpathBits special flags for fast parsing
729e4ab9 271 */
f3c0d7a5 272 void set(StringPiece source, UErrorCode &status, uint32_t fastpathBits = 0);
729e4ab9
A
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);
374ca955 280
b75a7d8f 281 /**
729e4ab9
A
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
b75a7d8f
A
293 */
294 UBool isZero(void) const;
295
729e4ab9
A
296 /** Test for a Nan
297 * @return TRUE if the number is a NaN
298 */
4388f060 299 UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}
729e4ab9 300
4388f060 301 UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);}
729e4ab9
A
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 */
4388f060 310 void setToZero() {uprv_decNumberZero(fDecNumber);}
729e4ab9
A
311
312 /** get the number of digits in the decimal number */
4388f060 313 int32_t digits() const {return fDecNumber->digits;}
729e4ab9 314
b75a7d8f 315 /**
729e4ab9
A
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.
2ca993e8 319 * result is guaranteed to be trimmed.
729e4ab9
A
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.
b75a7d8f 328 */
729e4ab9
A
329 void ensureCapacity(int32_t requestedSize, UErrorCode &status);
330
4388f060 331 UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;}
729e4ab9
A
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
b75a7d8f 354
b75a7d8f 355 /**
729e4ab9
A
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
2ca993e8
A
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 */
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);
729e4ab9
A
435
436private:
437 /*
b75a7d8f
A
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'.
729e4ab9
A
457 *
458 * int32_t fDecimalAt;
459 * int32_t fCount;
460 * UBool fIsPositive;
461 * char *fDigits;
462 * DecimalFormat::ERoundingMode fRoundingMode;
b75a7d8f 463 */
b75a7d8f 464
4388f060
A
465public:
466 decContext fContext; // public access to status flags.
b75a7d8f 467
4388f060 468private:
729e4ab9
A
469 decNumber *fDecNumber;
470 MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS> fStorage;
b75a7d8f 471
729e4ab9
A
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.
b75a7d8f 475 */
51004dcb
A
476 union DoubleOrInt64 {
477 double fDouble;
478 int64_t fInt64;
479 } fUnion;
480 enum EHave {
481 kNone=0,
2ca993e8 482 kDouble
51004dcb 483 } fHave;
729e4ab9
A
484
485
b75a7d8f 486
374ca955 487 UBool shouldRoundUp(int32_t maximumDigits) const;
51004dcb
A
488
489 public:
490
57a6839d 491#if U_OVERRIDE_CXX_ALLOCATION
51004dcb
A
492 using UMemory::operator new;
493 using UMemory::operator delete;
57a6839d
A
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
f3c0d7a5
A
498
499 static double U_EXPORT2 decimalStrToDouble(char *decstr, char **end);
51004dcb
A
500
501 /**
502 * Placement new for stack usage
503 * @internal
504 */
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 */
511 static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/) U_NO_THROW {}
512
513 private:
514 inline void internalSetDouble(double d) {
515 fHave = kDouble;
516 fUnion.fDouble=d;
517 }
51004dcb
A
518 inline void internalClear() {
519 fHave = kNone;
520 }
b75a7d8f 521};
729e4ab9 522
46f4442e 523
b75a7d8f 524U_NAMESPACE_END
46f4442e
A
525
526#endif // #if !UCONFIG_NO_FORMATTING
b75a7d8f
A
527#endif // _DIGITLST
528
529//eof