]>
Commit | Line | Data |
---|---|---|
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 | |
39 | typedef 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 | ||
51 | U_NAMESPACE_BEGIN | |
52 | ||
729e4ab9 A |
53 | class 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) | |
65 | template 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 | 122 | class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy |
b75a7d8f | 123 | public: |
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 | ||
346 | private: | |
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 | |
375 | private: | |
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 | 394 | U_NAMESPACE_END |
46f4442e A |
395 | |
396 | #endif // #if !UCONFIG_NO_FORMATTING | |
b75a7d8f A |
397 | #endif // _DIGITLST |
398 | ||
399 | //eof |