]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/digitlst.h
ICU-511.35.tar.gz
[apple/icu.git] / icuSources / i18n / digitlst.h
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