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