]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/digitlst.h
ICU-511.25.tar.gz
[apple/icu.git] / icuSources / i18n / digitlst.h
CommitLineData
b75a7d8f
A
1/*
2******************************************************************************
3*
51004dcb 4* Copyright (C) 1997-2012, International Business Machines
b75a7d8f
A
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
b75a7d8f 27#include "unicode/uobject.h"
46f4442e
A
28
29#if !UCONFIG_NO_FORMATTING
03115e54 30#include "unicode/decimfmt.h"
b75a7d8f 31#include <float.h>
729e4ab9
A
32#include "decContext.h"
33#include "decNumber.h"
34#include "cmemory.h"
b75a7d8f 35
374ca955 36// Decimal digits in a 64-bit int
374ca955 37#define INT64_DIGITS 19
b75a7d8f
A
38
39typedef enum EDigitListValues {
374ca955
A
40 MAX_DBL_DIGITS = DBL_DIG,
41 MAX_I64_DIGITS = INT64_DIGITS,
42 MAX_DIGITS = MAX_I64_DIGITS,
b75a7d8f
A
43 MAX_EXPONENT = DBL_DIG,
44 DIGIT_PADDING = 3,
729e4ab9 45 DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed.
b75a7d8f
A
46
47 // "+." + fDigits + "e" + fDecimalAt
374ca955 48 MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
b75a7d8f
A
49} EDigitListValues;
50
51U_NAMESPACE_BEGIN
52
729e4ab9
A
53class CharString;
54
55// Export an explicit template instantiation of the MaybeStackHeaderAndArray that
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 library.
60//
61// Macintosh produces duplicate definition linker errors with the explicit template
62// instantiation.
63//
4388f060 64#if !U_PLATFORM_IS_DARWIN_BASED
729e4ab9
A
65template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>;
66#endif
67
68
51004dcb
A
69enum EStackMode { kOnStack };
70
71enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 };
72
b75a7d8f 73/**
729e4ab9
A
74 * Digit List is actually a Decimal Floating Point number.
75 * The original implementation has been replaced by a thin wrapper onto a
76 * decimal number from the decNumber library.
77 *
78 * The original DigitList API has been retained, to minimize the impact of
79 * the change on the rest of the ICU formatting code.
80 *
81 * The change to decNumber enables support for big decimal numbers, and
82 * allows rounding computations to be done directly in decimal, avoiding
83 * extra, and inaccurate, conversions to and from doubles.
84 *
85 * Original DigitList comments:
86 *
b75a7d8f
A
87 * Digit List utility class. Private to DecimalFormat. Handles the transcoding
88 * between numeric values and strings of characters. Only handles
89 * non-negative numbers. The division of labor between DigitList and
90 * DecimalFormat is that DigitList handles the radix 10 representation
91 * issues; DecimalFormat handles the locale-specific issues such as
92 * positive/negative, grouping, decimal point, currency, and so on.
93 * <P>
94 * A DigitList is really a representation of a floating point value.
95 * It may be an integer value; we assume that a double has sufficient
96 * precision to represent all digits of a long.
97 * <P>
98 * The DigitList representation consists of a string of characters,
99 * which are the digits radix 10, from '0' to '9'. It also has a radix
100 * 10 exponent associated with it. The value represented by a DigitList
101 * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
102 * derived by placing all the digits of the list to the right of the
103 * decimal point, by 10^exponent.
729e4ab9
A
104 *
105 * --------
106 *
107 * DigitList vs. decimalNumber:
108 *
109 * DigitList stores digits with the most significant first.
110 * decNumber stores digits with the least significant first.
111 *
112 * DigitList, decimal point is before the most significant.
113 * decNumber, decimal point is after the least signficant digit.
114 *
115 * digitList: 0.ddddd * 10 ^ exp
116 * decNumber: ddddd. * 10 ^ exp
117 *
118 * digitList exponent = decNumber exponent + digit count
119 *
120 * digitList, digits are platform invariant chars, '0' - '9'
121 * decNumber, digits are binary, one per byte, 0 - 9.
122 *
123 * (decNumber library is configurable in how digits are stored, ICU has configured
124 * it this way for convenience in replacing the old DigitList implementation.)
b75a7d8f 125 */
729e4ab9 126class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy
b75a7d8f 127public:
729e4ab9 128
b75a7d8f
A
129 DigitList();
130 ~DigitList();
131
132 /* copy constructor
133 * @param DigitList The object to be copied.
134 * @return the newly created object.
135 */
136 DigitList(const DigitList&); // copy constructor
137
138 /* assignment operator
139 * @param DigitList The object to be copied.
140 * @return the newly created object.
141 */
142 DigitList& operator=(const DigitList&); // assignment operator
143
144 /**
145 * Return true if another object is semantically equal to this one.
146 * @param other The DigitList to be compared for equality
147 * @return true if another object is semantically equal to this one.
148 * return false otherwise.
149 */
150 UBool operator==(const DigitList& other) const;
151
729e4ab9
A
152 int32_t compare(const DigitList& other);
153
154
4388f060 155 inline UBool operator!=(const DigitList& other) const { return !operator==(other); }
b75a7d8f
A
156
157 /**
158 * Clears out the digits.
159 * Use before appending them.
160 * Typically, you set a series of digits with append, then at the point
161 * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount;
162 * then go on appending digits.
163 */
164 void clear(void);
165
166 /**
729e4ab9
A
167 * Remove, by rounding, any fractional part of the decimal number,
168 * leaving an integer value.
169 */
170 void toIntegralValue();
171
172 /**
173 * Appends digits to the list.
174 * CAUTION: this function is not recommended for new code.
175 * In the original DigitList implementation, decimal numbers were
176 * parsed by appending them to a digit list as they were encountered.
177 * With the revamped DigitList based on decNumber, append is very
178 * inefficient, and the interaction with the exponent value is confusing.
179 * Best avoided.
180 * TODO: remove this function once all use has been replaced.
181 * TODO: describe alternative to append()
b75a7d8f
A
182 * @param digit The digit to be appended.
183 */
729e4ab9 184 void append(char digit);
b75a7d8f
A
185
186 /**
187 * Utility routine to get the value of the digit list
188 * Returns 0.0 if zero length.
189 * @return the value of the digit list.
190 */
729e4ab9 191 double getDouble(void) const;
b75a7d8f
A
192
193 /**
194 * Utility routine to get the value of the digit list
195 * Make sure that fitsIntoLong() is called before calling this function.
196 * Returns 0 if zero length.
197 * @return the value of the digit list, return 0 if it is zero length
198 */
374ca955
A
199 int32_t getLong(void) /*const*/;
200
201 /**
202 * Utility routine to get the value of the digit list
203 * Make sure that fitsIntoInt64() is called before calling this function.
204 * Returns 0 if zero length.
205 * @return the value of the digit list, return 0 if it is zero length
206 */
207 int64_t getInt64(void) /*const*/;
b75a7d8f 208
729e4ab9
A
209 /**
210 * Utility routine to get the value of the digit list as a decimal string.
211 */
212 void getDecimal(CharString &str, UErrorCode &status);
213
b75a7d8f
A
214 /**
215 * Return true if the number represented by this object can fit into
216 * a long.
217 * @param ignoreNegativeZero True if negative zero is ignored.
218 * @return true if the number represented by this object can fit into
219 * a long, return false otherwise.
220 */
374ca955
A
221 UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/;
222
223 /**
224 * Return true if the number represented by this object can fit into
225 * an int64_t.
226 * @param ignoreNegativeZero True if negative zero is ignored.
227 * @return true if the number represented by this object can fit into
228 * a long, return false otherwise.
229 */
230 UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/;
b75a7d8f
A
231
232 /**
729e4ab9 233 * Utility routine to set the value of the digit list from a double.
b75a7d8f 234 * @param source The value to be set
b75a7d8f 235 */
729e4ab9 236 void set(double source);
b75a7d8f
A
237
238 /**
239 * Utility routine to set the value of the digit list from a long.
240 * If a non-zero maximumDigits is specified, no more than that number of
241 * significant digits will be produced.
242 * @param source The value to be set
b75a7d8f 243 */
729e4ab9 244 void set(int32_t source);
b75a7d8f 245
374ca955
A
246 /**
247 * Utility routine to set the value of the digit list from an int64.
248 * If a non-zero maximumDigits is specified, no more than that number of
249 * significant digits will be produced.
250 * @param source The value to be set
374ca955 251 */
729e4ab9
A
252 void set(int64_t source);
253
51004dcb
A
254 /**
255 * Utility routine to set the value of the digit list from an int64.
256 * Does not set the decnumber unless requested later
257 * If a non-zero maximumDigits is specified, no more than that number of
258 * significant digits will be produced.
259 * @param source The value to be set
260 */
261 void setInteger(int64_t source);
262
729e4ab9
A
263 /**
264 * Utility routine to set the value of the digit list from a decimal number
265 * string.
266 * @param source The value to be set. The string must be nul-terminated.
51004dcb 267 * @param fastpathBits special flags for fast parsing
729e4ab9 268 */
51004dcb 269 void set(const StringPiece &source, UErrorCode &status, uint32_t fastpathBits = 0);
729e4ab9
A
270
271 /**
272 * Multiply this = this * arg
273 * This digitlist will be expanded if necessary to accomodate the result.
274 * @param arg the number to multiply by.
275 */
276 void mult(const DigitList &arg, UErrorCode &status);
374ca955 277
b75a7d8f 278 /**
729e4ab9
A
279 * Divide this = this / arg
280 */
281 void div(const DigitList &arg, UErrorCode &status);
282
283 // The following functions replace direct access to the original DigitList implmentation
284 // data structures.
285
286 void setRoundingMode(DecimalFormat::ERoundingMode m);
287
288 /** Test a number for zero.
289 * @return TRUE if the number is zero
b75a7d8f
A
290 */
291 UBool isZero(void) const;
292
729e4ab9
A
293 /** Test for a Nan
294 * @return TRUE if the number is a NaN
295 */
4388f060 296 UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}
729e4ab9 297
4388f060 298 UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);}
729e4ab9
A
299
300 /** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */
301 void reduce();
302
303 /** Remove trailing fraction zeros, adjust exponent accordingly. */
304 void trim();
305
306 /** Set to zero */
4388f060 307 void setToZero() {uprv_decNumberZero(fDecNumber);}
729e4ab9
A
308
309 /** get the number of digits in the decimal number */
4388f060 310 int32_t digits() const {return fDecNumber->digits;}
729e4ab9 311
b75a7d8f 312 /**
729e4ab9
A
313 * Round the number to the given number of digits.
314 * @param maximumDigits The maximum number of digits to be shown.
315 * Upon return, count will be less than or equal to maximumDigits.
316 */
317 void round(int32_t maximumDigits);
318
319 void roundFixedPoint(int32_t maximumFractionDigits);
320
321 /** Ensure capacity for digits. Grow the storage if it is currently less than
322 * the requested size. Capacity is not reduced if it is already greater
323 * than requested.
b75a7d8f 324 */
729e4ab9
A
325 void ensureCapacity(int32_t requestedSize, UErrorCode &status);
326
4388f060 327 UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;}
729e4ab9
A
328 void setPositive(UBool s);
329
330 void setDecimalAt(int32_t d);
331 int32_t getDecimalAt();
332
333 void setCount(int32_t c);
334 int32_t getCount() const;
335
336 /**
337 * Set the digit in platform (invariant) format, from '0'..'9'
338 * @param i index of digit
339 * @param v digit value, from '0' to '9' in platform invariant format
340 */
341 void setDigit(int32_t i, char v);
342
343 /**
344 * Get the digit in platform (invariant) format, from '0'..'9' inclusive
345 * @param i index of digit
346 * @return invariant format of the digit
347 */
348 char getDigit(int32_t i);
349
b75a7d8f 350
b75a7d8f 351 /**
729e4ab9
A
352 * Get the digit's value, as an integer from 0..9 inclusive.
353 * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t.
354 * @param i index of digit
355 * @return value of that digit
356 */
357 uint8_t getDigitValue(int32_t i);
358
359
360private:
361 /*
b75a7d8f
A
362 * These data members are intentionally public and can be set directly.
363 *<P>
364 * The value represented is given by placing the decimal point before
365 * fDigits[fDecimalAt]. If fDecimalAt is < 0, then leading zeros between
366 * the decimal point and the first nonzero digit are implied. If fDecimalAt
367 * is > fCount, then trailing zeros between the fDigits[fCount-1] and the
368 * decimal point are implied.
369 * <P>
370 * Equivalently, the represented value is given by f * 10^fDecimalAt. Here
371 * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to
372 * the right of the decimal.
373 * <P>
374 * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero. We
375 * don't allow denormalized numbers because our exponent is effectively of
376 * unlimited magnitude. The fCount value contains the number of significant
377 * digits present in fDigits[].
378 * <P>
379 * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i]
380 * for all i <= fCount == '0'.
729e4ab9
A
381 *
382 * int32_t fDecimalAt;
383 * int32_t fCount;
384 * UBool fIsPositive;
385 * char *fDigits;
386 * DecimalFormat::ERoundingMode fRoundingMode;
b75a7d8f 387 */
b75a7d8f 388
4388f060
A
389public:
390 decContext fContext; // public access to status flags.
b75a7d8f 391
4388f060 392private:
729e4ab9
A
393 decNumber *fDecNumber;
394 MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS> fStorage;
b75a7d8f 395
729e4ab9
A
396 /* Cached double value corresponding to this decimal number.
397 * This is an optimization for the formatting implementation, which may
398 * ask for the double value multiple times.
b75a7d8f 399 */
51004dcb
A
400 union DoubleOrInt64 {
401 double fDouble;
402 int64_t fInt64;
403 } fUnion;
404 enum EHave {
405 kNone=0,
406 kDouble,
407 kInt64
408 } fHave;
729e4ab9
A
409
410
b75a7d8f 411
374ca955 412 UBool shouldRoundUp(int32_t maximumDigits) const;
51004dcb
A
413
414 public:
415
416 using UMemory::operator new;
417 using UMemory::operator delete;
418
419 /**
420 * Placement new for stack usage
421 * @internal
422 */
423 static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode /*mode*/) U_NO_THROW { return onStack; }
424
425 /**
426 * Placement delete for stack usage
427 * @internal
428 */
429 static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/) U_NO_THROW {}
430
431 private:
432 inline void internalSetDouble(double d) {
433 fHave = kDouble;
434 fUnion.fDouble=d;
435 }
436 inline void internalSetInt64(int64_t d) {
437 fHave = kInt64;
438 fUnion.fInt64=d;
439 }
440 inline void internalClear() {
441 fHave = kNone;
442 }
b75a7d8f 443};
729e4ab9 444
46f4442e 445
b75a7d8f 446U_NAMESPACE_END
46f4442e
A
447
448#endif // #if !UCONFIG_NO_FORMATTING
b75a7d8f
A
449#endif // _DIGITLST
450
451//eof