Line data Source code
1 : // © 2016 and later: Unicode, Inc. and others.
2 : // License & terms of use: http://www.unicode.org/copyright.html
3 : /*
4 : ******************************************************************************
5 : *
6 : * Copyright (C) 1997-2015, International Business Machines
7 : * Corporation and others. All Rights Reserved.
8 : *
9 : ******************************************************************************
10 : *
11 : * File DIGITLST.H
12 : *
13 : * Modification History:
14 : *
15 : * Date Name Description
16 : * 02/25/97 aliu Converted from java.
17 : * 03/21/97 clhuang Updated per C++ implementation.
18 : * 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char.
19 : * 09/09/97 aliu Adapted for exponential notation support.
20 : * 08/02/98 stephen Added nearest/even rounding
21 : * 06/29/99 stephen Made LONG_DIGITS a macro to satisfy SUN compiler
22 : * 07/09/99 stephen Removed kMaxCount (unused, for HP compiler)
23 : ******************************************************************************
24 : */
25 :
26 : #ifndef DIGITLST_H
27 : #define DIGITLST_H
28 :
29 : #include "unicode/uobject.h"
30 :
31 : #if !UCONFIG_NO_FORMATTING
32 : #include "unicode/decimfmt.h"
33 : #include <float.h>
34 : #include "decContext.h"
35 : #include "decNumber.h"
36 : #include "cmemory.h"
37 :
38 : // Decimal digits in a 64-bit int
39 : #define INT64_DIGITS 19
40 :
41 : typedef enum EDigitListValues {
42 : MAX_DBL_DIGITS = DBL_DIG,
43 : MAX_I64_DIGITS = INT64_DIGITS,
44 : MAX_DIGITS = MAX_I64_DIGITS,
45 : MAX_EXPONENT = DBL_DIG,
46 : DIGIT_PADDING = 3,
47 : DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed.
48 :
49 : // "+." + fDigits + "e" + fDecimalAt
50 : MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
51 : } EDigitListValues;
52 :
53 : U_NAMESPACE_BEGIN
54 :
55 : class CharString;
56 : class DigitInterval;
57 :
58 : // Export an explicit template instantiation of the MaybeStackHeaderAndArray that
59 : // is used as a data member of DigitList.
60 : //
61 : // MSVC requires this, even though it should not be necessary.
62 : // No direct access to the MaybeStackHeaderAndArray leaks out of the i18n library.
63 : //
64 : // Macintosh produces duplicate definition linker errors with the explicit template
65 : // instantiation.
66 : //
67 : #if !U_PLATFORM_IS_DARWIN_BASED
68 : template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS>;
69 : #endif
70 :
71 :
72 : enum EStackMode { kOnStack };
73 :
74 : enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 };
75 :
76 : /**
77 : * Digit List is actually a Decimal Floating Point number.
78 : * The original implementation has been replaced by a thin wrapper onto a
79 : * decimal number from the decNumber library.
80 : *
81 : * The original DigitList API has been retained, to minimize the impact of
82 : * the change on the rest of the ICU formatting code.
83 : *
84 : * The change to decNumber enables support for big decimal numbers, and
85 : * allows rounding computations to be done directly in decimal, avoiding
86 : * extra, and inaccurate, conversions to and from doubles.
87 : *
88 : * Original DigitList comments:
89 : *
90 : * Digit List utility class. Private to DecimalFormat. Handles the transcoding
91 : * between numeric values and strings of characters. Only handles
92 : * non-negative numbers. The division of labor between DigitList and
93 : * DecimalFormat is that DigitList handles the radix 10 representation
94 : * issues; DecimalFormat handles the locale-specific issues such as
95 : * positive/negative, grouping, decimal point, currency, and so on.
96 : * <P>
97 : * A DigitList is really a representation of a floating point value.
98 : * It may be an integer value; we assume that a double has sufficient
99 : * precision to represent all digits of a long.
100 : * <P>
101 : * The DigitList representation consists of a string of characters,
102 : * which are the digits radix 10, from '0' to '9'. It also has a radix
103 : * 10 exponent associated with it. The value represented by a DigitList
104 : * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
105 : * derived by placing all the digits of the list to the right of the
106 : * decimal point, by 10^exponent.
107 : *
108 : * --------
109 : *
110 : * DigitList vs. decimalNumber:
111 : *
112 : * DigitList stores digits with the most significant first.
113 : * decNumber stores digits with the least significant first.
114 : *
115 : * DigitList, decimal point is before the most significant.
116 : * decNumber, decimal point is after the least signficant digit.
117 : *
118 : * digitList: 0.ddddd * 10 ^ exp
119 : * decNumber: ddddd. * 10 ^ exp
120 : *
121 : * digitList exponent = decNumber exponent + digit count
122 : *
123 : * digitList, digits are platform invariant chars, '0' - '9'
124 : * decNumber, digits are binary, one per byte, 0 - 9.
125 : *
126 : * (decNumber library is configurable in how digits are stored, ICU has configured
127 : * it this way for convenience in replacing the old DigitList implementation.)
128 : */
129 : class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy
130 : public:
131 :
132 : DigitList();
133 : ~DigitList();
134 :
135 : /* copy constructor
136 : * @param DigitList The object to be copied.
137 : * @return the newly created object.
138 : */
139 : DigitList(const DigitList&); // copy constructor
140 :
141 : /* assignment operator
142 : * @param DigitList The object to be copied.
143 : * @return the newly created object.
144 : */
145 : DigitList& operator=(const DigitList&); // assignment operator
146 :
147 : /**
148 : * Return true if another object is semantically equal to this one.
149 : * @param other The DigitList to be compared for equality
150 : * @return true if another object is semantically equal to this one.
151 : * return false otherwise.
152 : */
153 : UBool operator==(const DigitList& other) const;
154 :
155 : int32_t compare(const DigitList& other);
156 :
157 :
158 : inline UBool operator!=(const DigitList& other) const { return !operator==(other); }
159 :
160 : /**
161 : * Clears out the digits.
162 : * Use before appending them.
163 : * Typically, you set a series of digits with append, then at the point
164 : * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount;
165 : * then go on appending digits.
166 : */
167 : void clear(void);
168 :
169 : /**
170 : * Remove, by rounding, any fractional part of the decimal number,
171 : * leaving an integer value.
172 : */
173 : void toIntegralValue();
174 :
175 : /**
176 : * Appends digits to the list.
177 : * CAUTION: this function is not recommended for new code.
178 : * In the original DigitList implementation, decimal numbers were
179 : * parsed by appending them to a digit list as they were encountered.
180 : * With the revamped DigitList based on decNumber, append is very
181 : * inefficient, and the interaction with the exponent value is confusing.
182 : * Best avoided.
183 : * TODO: remove this function once all use has been replaced.
184 : * TODO: describe alternative to append()
185 : * @param digit The digit to be appended.
186 : */
187 : void append(char digit);
188 :
189 : /**
190 : * Utility routine to get the value of the digit list
191 : * Returns 0.0 if zero length.
192 : * @return the value of the digit list.
193 : */
194 : double getDouble(void) const;
195 :
196 : /**
197 : * Utility routine to get the value of the digit list
198 : * Make sure that fitsIntoLong() is called before calling this function.
199 : * Returns 0 if zero length.
200 : * @return the value of the digit list, return 0 if it is zero length
201 : */
202 : int32_t getLong(void) /*const*/;
203 :
204 : /**
205 : * Utility routine to get the value of the digit list
206 : * Make sure that fitsIntoInt64() is called before calling this function.
207 : * Returns 0 if zero length.
208 : * @return the value of the digit list, return 0 if it is zero length
209 : */
210 : int64_t getInt64(void) /*const*/;
211 :
212 : /**
213 : * Utility routine to get the value of the digit list as a decimal string.
214 : */
215 : void getDecimal(CharString &str, UErrorCode &status);
216 :
217 : /**
218 : * Return true if the number represented by this object can fit into
219 : * a long.
220 : * @param ignoreNegativeZero True if negative zero is ignored.
221 : * @return true if the number represented by this object can fit into
222 : * a long, return false otherwise.
223 : */
224 : UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/;
225 :
226 : /**
227 : * Return true if the number represented by this object can fit into
228 : * an int64_t.
229 : * @param ignoreNegativeZero True if negative zero is ignored.
230 : * @return true if the number represented by this object can fit into
231 : * a long, return false otherwise.
232 : */
233 : UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/;
234 :
235 : /**
236 : * Utility routine to set the value of the digit list from a double.
237 : * @param source The value to be set
238 : */
239 : void set(double source);
240 :
241 : /**
242 : * Utility routine to set the value of the digit list from a long.
243 : * If a non-zero maximumDigits is specified, no more than that number of
244 : * significant digits will be produced.
245 : * @param source The value to be set
246 : */
247 : void set(int32_t source);
248 :
249 : /**
250 : * Utility routine to set the value of the digit list from an int64.
251 : * If a non-zero maximumDigits is specified, no more than that number of
252 : * significant digits will be produced.
253 : * @param source The value to be set
254 : */
255 : void set(int64_t source);
256 :
257 : /**
258 : * Utility routine to set the value of the digit list from an int64.
259 : * Does not set the decnumber unless requested later
260 : * If a non-zero maximumDigits is specified, no more than that number of
261 : * significant digits will be produced.
262 : * @param source The value to be set
263 : */
264 : void setInteger(int64_t source);
265 :
266 : /**
267 : * Utility routine to set the value of the digit list from a decimal number
268 : * string.
269 : * @param source The value to be set. The string must be nul-terminated.
270 : * @param fastpathBits special flags for fast parsing
271 : */
272 : void set(StringPiece source, UErrorCode &status, uint32_t fastpathBits = 0);
273 :
274 : /**
275 : * Multiply this = this * arg
276 : * This digitlist will be expanded if necessary to accomodate the result.
277 : * @param arg the number to multiply by.
278 : */
279 : void mult(const DigitList &arg, UErrorCode &status);
280 :
281 : /**
282 : * Divide this = this / arg
283 : */
284 : void div(const DigitList &arg, UErrorCode &status);
285 :
286 : // The following functions replace direct access to the original DigitList implmentation
287 : // data structures.
288 :
289 : void setRoundingMode(DecimalFormat::ERoundingMode m);
290 :
291 : /** Test a number for zero.
292 : * @return TRUE if the number is zero
293 : */
294 : UBool isZero(void) const;
295 :
296 : /** Test for a Nan
297 : * @return TRUE if the number is a NaN
298 : */
299 0 : UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}
300 :
301 0 : UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);}
302 :
303 : /** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */
304 : void reduce();
305 :
306 : /** Remove trailing fraction zeros, adjust exponent accordingly. */
307 : void trim();
308 :
309 : /** Set to zero */
310 0 : void setToZero() {uprv_decNumberZero(fDecNumber);}
311 :
312 : /** get the number of digits in the decimal number */
313 0 : int32_t digits() const {return fDecNumber->digits;}
314 :
315 : /**
316 : * Round the number to the given number of digits.
317 : * @param maximumDigits The maximum number of digits to be shown.
318 : * Upon return, count will be less than or equal to maximumDigits.
319 : * result is guaranteed to be trimmed.
320 : */
321 : void round(int32_t maximumDigits);
322 :
323 : void roundFixedPoint(int32_t maximumFractionDigits);
324 :
325 : /** Ensure capacity for digits. Grow the storage if it is currently less than
326 : * the requested size. Capacity is not reduced if it is already greater
327 : * than requested.
328 : */
329 : void ensureCapacity(int32_t requestedSize, UErrorCode &status);
330 :
331 0 : UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;}
332 : void setPositive(UBool s);
333 :
334 : void setDecimalAt(int32_t d);
335 : int32_t getDecimalAt();
336 :
337 : void setCount(int32_t c);
338 : int32_t getCount() const;
339 :
340 : /**
341 : * Set the digit in platform (invariant) format, from '0'..'9'
342 : * @param i index of digit
343 : * @param v digit value, from '0' to '9' in platform invariant format
344 : */
345 : void setDigit(int32_t i, char v);
346 :
347 : /**
348 : * Get the digit in platform (invariant) format, from '0'..'9' inclusive
349 : * @param i index of digit
350 : * @return invariant format of the digit
351 : */
352 : char getDigit(int32_t i);
353 :
354 :
355 : /**
356 : * Get the digit's value, as an integer from 0..9 inclusive.
357 : * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t.
358 : * @param i index of digit
359 : * @return value of that digit
360 : */
361 : uint8_t getDigitValue(int32_t i);
362 :
363 : /**
364 : * Gets the upper bound exponent for this value. For 987, returns 3
365 : * because 10^3 is the smallest power of 10 that is just greater than
366 : * 987.
367 : */
368 : int32_t getUpperExponent() const;
369 :
370 : /**
371 : * Gets the lower bound exponent for this value. For 98.7, returns -1
372 : * because the right most digit, is the 10^-1 place.
373 : */
374 0 : int32_t getLowerExponent() const { return fDecNumber->exponent; }
375 :
376 : /**
377 : * Sets result to the smallest DigitInterval needed to display this
378 : * DigitList in fixed point form and returns result.
379 : */
380 : DigitInterval& getSmallestInterval(DigitInterval &result) const;
381 :
382 : /**
383 : * Like getDigitValue, but the digit is identified by exponent.
384 : * For example, getDigitByExponent(7) returns the 10^7 place of this
385 : * DigitList. Unlike getDigitValue, there are no upper or lower bounds
386 : * for passed parameter. Instead, getDigitByExponent returns 0 if
387 : * the exponent falls outside the interval for this DigitList.
388 : */
389 : uint8_t getDigitByExponent(int32_t exponent) const;
390 :
391 : /**
392 : * Appends the digits in this object to a CharString.
393 : * 3 is appended as (char) 3, not '3'
394 : */
395 : void appendDigitsTo(CharString &str, UErrorCode &status) const;
396 :
397 : /**
398 : * Equivalent to roundFixedPoint(-digitExponent) except unlike
399 : * roundFixedPoint, this works for any digitExponent value.
400 : * If maxSigDigits is set then this instance is rounded to have no more
401 : * than maxSigDigits. The end result is guaranteed to be trimmed.
402 : */
403 : void roundAtExponent(int32_t digitExponent, int32_t maxSigDigits=INT32_MAX);
404 :
405 : /**
406 : * Quantizes according to some amount and rounds according to the
407 : * context of this instance. Quantizing 3.233 with 0.05 gives 3.25.
408 : */
409 : void quantize(const DigitList &amount, UErrorCode &status);
410 :
411 : /**
412 : * Like toScientific but only returns the exponent
413 : * leaving this instance unchanged.
414 : */
415 : int32_t getScientificExponent(
416 : int32_t minIntDigitCount, int32_t exponentMultiplier) const;
417 :
418 : /**
419 : * Converts this instance to scientific notation. This instance
420 : * becomes the mantissa and the exponent is returned.
421 : * @param minIntDigitCount minimum integer digits in mantissa
422 : * Exponent is set so that the actual number of integer digits
423 : * in mantissa is as close to the minimum as possible.
424 : * @param exponentMultiplier The exponent is always a multiple of
425 : * This number. Usually 1, but set to 3 for engineering notation.
426 : * @return exponent
427 : */
428 : int32_t toScientific(
429 : int32_t minIntDigitCount, int32_t exponentMultiplier);
430 :
431 : /**
432 : * Shifts decimal to the right.
433 : */
434 : void shiftDecimalRight(int32_t numPlaces);
435 :
436 : private:
437 : /*
438 : * These data members are intentionally public and can be set directly.
439 : *<P>
440 : * The value represented is given by placing the decimal point before
441 : * fDigits[fDecimalAt]. If fDecimalAt is < 0, then leading zeros between
442 : * the decimal point and the first nonzero digit are implied. If fDecimalAt
443 : * is > fCount, then trailing zeros between the fDigits[fCount-1] and the
444 : * decimal point are implied.
445 : * <P>
446 : * Equivalently, the represented value is given by f * 10^fDecimalAt. Here
447 : * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to
448 : * the right of the decimal.
449 : * <P>
450 : * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero. We
451 : * don't allow denormalized numbers because our exponent is effectively of
452 : * unlimited magnitude. The fCount value contains the number of significant
453 : * digits present in fDigits[].
454 : * <P>
455 : * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i]
456 : * for all i <= fCount == '0'.
457 : *
458 : * int32_t fDecimalAt;
459 : * int32_t fCount;
460 : * UBool fIsPositive;
461 : * char *fDigits;
462 : * DecimalFormat::ERoundingMode fRoundingMode;
463 : */
464 :
465 : public:
466 : decContext fContext; // public access to status flags.
467 :
468 : private:
469 : decNumber *fDecNumber;
470 : MaybeStackHeaderAndArray<decNumber, char, DEFAULT_DIGITS> fStorage;
471 :
472 : /* Cached double value corresponding to this decimal number.
473 : * This is an optimization for the formatting implementation, which may
474 : * ask for the double value multiple times.
475 : */
476 : union DoubleOrInt64 {
477 : double fDouble;
478 : int64_t fInt64;
479 : } fUnion;
480 : enum EHave {
481 : kNone=0,
482 : kDouble
483 : } fHave;
484 :
485 :
486 :
487 : UBool shouldRoundUp(int32_t maximumDigits) const;
488 :
489 : public:
490 :
491 : #if U_OVERRIDE_CXX_ALLOCATION
492 : using UMemory::operator new;
493 : using UMemory::operator delete;
494 : #else
495 : static inline void * U_EXPORT2 operator new(size_t size) U_NO_THROW { return ::operator new(size); };
496 : static inline void U_EXPORT2 operator delete(void *ptr ) U_NO_THROW { ::operator delete(ptr); };
497 : #endif
498 :
499 : static double U_EXPORT2 decimalStrToDouble(char *decstr, char **end);
500 :
501 : /**
502 : * Placement new for stack usage
503 : * @internal
504 : */
505 0 : static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode /*mode*/) U_NO_THROW { return onStack; }
506 :
507 : /**
508 : * Placement delete for stack usage
509 : * @internal
510 : */
511 : static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/) U_NO_THROW {}
512 :
513 : private:
514 0 : inline void internalSetDouble(double d) {
515 0 : fHave = kDouble;
516 0 : fUnion.fDouble=d;
517 0 : }
518 0 : inline void internalClear() {
519 0 : fHave = kNone;
520 0 : }
521 : };
522 :
523 :
524 : U_NAMESPACE_END
525 :
526 : #endif // #if !UCONFIG_NO_FORMATTING
527 : #endif // _DIGITLST
528 :
529 : //eof
|