|
1 /* |
|
2 ****************************************************************************** |
|
3 * |
|
4 * Copyright (C) 1997-2012, International Business Machines |
|
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 |
|
27 #include "unicode/uobject.h" |
|
28 |
|
29 #if !UCONFIG_NO_FORMATTING |
|
30 #include "unicode/decimfmt.h" |
|
31 #include <float.h> |
|
32 #include "decContext.h" |
|
33 #include "decNumber.h" |
|
34 #include "cmemory.h" |
|
35 |
|
36 // Decimal digits in a 64-bit int |
|
37 #define INT64_DIGITS 19 |
|
38 |
|
39 typedef enum EDigitListValues { |
|
40 MAX_DBL_DIGITS = DBL_DIG, |
|
41 MAX_I64_DIGITS = INT64_DIGITS, |
|
42 MAX_DIGITS = MAX_I64_DIGITS, |
|
43 MAX_EXPONENT = DBL_DIG, |
|
44 DIGIT_PADDING = 3, |
|
45 DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed. |
|
46 |
|
47 // "+." + fDigits + "e" + fDecimalAt |
|
48 MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT |
|
49 } EDigitListValues; |
|
50 |
|
51 U_NAMESPACE_BEGIN |
|
52 |
|
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 !U_PLATFORM_IS_DARWIN_BASED |
|
65 template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>; |
|
66 #endif |
|
67 |
|
68 |
|
69 enum EStackMode { kOnStack }; |
|
70 |
|
71 enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 }; |
|
72 |
|
73 /** |
|
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 * |
|
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. |
|
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.) |
|
125 */ |
|
126 class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy |
|
127 public: |
|
128 |
|
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 |
|
152 int32_t compare(const DigitList& other); |
|
153 |
|
154 |
|
155 inline UBool operator!=(const DigitList& other) const { return !operator==(other); } |
|
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 /** |
|
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() |
|
182 * @param digit The digit to be appended. |
|
183 */ |
|
184 void append(char digit); |
|
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 */ |
|
191 double getDouble(void) const; |
|
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 */ |
|
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*/; |
|
208 |
|
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 |
|
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 */ |
|
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*/; |
|
231 |
|
232 /** |
|
233 * Utility routine to set the value of the digit list from a double. |
|
234 * @param source The value to be set |
|
235 */ |
|
236 void set(double source); |
|
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 |
|
243 */ |
|
244 void set(int32_t source); |
|
245 |
|
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 |
|
251 */ |
|
252 void set(int64_t source); |
|
253 |
|
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 |
|
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. |
|
267 * @param fastpathBits special flags for fast parsing |
|
268 */ |
|
269 void set(const StringPiece &source, UErrorCode &status, uint32_t fastpathBits = 0); |
|
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); |
|
277 |
|
278 /** |
|
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 |
|
290 */ |
|
291 UBool isZero(void) const; |
|
292 |
|
293 /** Test for a Nan |
|
294 * @return TRUE if the number is a NaN |
|
295 */ |
|
296 UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);} |
|
297 |
|
298 UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);} |
|
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 */ |
|
307 void setToZero() {uprv_decNumberZero(fDecNumber);} |
|
308 |
|
309 /** get the number of digits in the decimal number */ |
|
310 int32_t digits() const {return fDecNumber->digits;} |
|
311 |
|
312 /** |
|
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. |
|
324 */ |
|
325 void ensureCapacity(int32_t requestedSize, UErrorCode &status); |
|
326 |
|
327 UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;} |
|
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 |
|
350 |
|
351 /** |
|
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 /* |
|
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'. |
|
381 * |
|
382 * int32_t fDecimalAt; |
|
383 * int32_t fCount; |
|
384 * UBool fIsPositive; |
|
385 * char *fDigits; |
|
386 * DecimalFormat::ERoundingMode fRoundingMode; |
|
387 */ |
|
388 |
|
389 public: |
|
390 decContext fContext; // public access to status flags. |
|
391 |
|
392 private: |
|
393 decNumber *fDecNumber; |
|
394 MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS> fStorage; |
|
395 |
|
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. |
|
399 */ |
|
400 union DoubleOrInt64 { |
|
401 double fDouble; |
|
402 int64_t fInt64; |
|
403 } fUnion; |
|
404 enum EHave { |
|
405 kNone=0, |
|
406 kDouble, |
|
407 kInt64 |
|
408 } fHave; |
|
409 |
|
410 |
|
411 |
|
412 UBool shouldRoundUp(int32_t maximumDigits) const; |
|
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 } |
|
443 }; |
|
444 |
|
445 |
|
446 U_NAMESPACE_END |
|
447 |
|
448 #endif // #if !UCONFIG_NO_FORMATTING |
|
449 #endif // _DIGITLST |
|
450 |
|
451 //eof |