]>
Commit | Line | Data |
---|---|---|
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 | |
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 | // | |
4388f060 | 64 | #if !U_PLATFORM_IS_DARWIN_BASED |
729e4ab9 A |
65 | template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>; |
66 | #endif | |
67 | ||
68 | ||
51004dcb A |
69 | enum EStackMode { kOnStack }; |
70 | ||
71 | enum 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 | 126 | class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy |
b75a7d8f | 127 | public: |
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 | ||
360 | private: | |
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 |
389 | public: |
390 | decContext fContext; // public access to status flags. | |
b75a7d8f | 391 | |
4388f060 | 392 | private: |
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 | 446 | U_NAMESPACE_END |
46f4442e A |
447 | |
448 | #endif // #if !UCONFIG_NO_FORMATTING | |
b75a7d8f A |
449 | #endif // _DIGITLST |
450 | ||
451 | //eof |