1 /*
2 *******************************************************************************
3 * Copyright (C) 2015, International Business Machines
4 * Corporation and others.  All Rights Reserved.
5 *******************************************************************************
6 * precision.h
7 *
8 * created on: 2015jan06
9 * created by: Travis Keep
10 */
11 
12 #ifndef __PRECISION_H__
13 #define __PRECISION_H__
14 
15 #include "unicode/uobject.h"
16 
17 #if !UCONFIG_NO_FORMATTING
18 #include "unicode/utypes.h"
19 
20 #include "digitinterval.h"
21 #include "digitlst.h"
22 #include "significantdigitinterval.h"
23 
24 U_NAMESPACE_BEGIN
25 
26 class VisibleDigits;
27 class VisibleDigitsWithExponent;
28 
29 
30 /**
31  * A precision manager for values to be formatted as fixed point.
32  * Handles rounding of number to prepare it for formatting.
33  */
34 class U_I18N_API FixedPrecision : public UMemory {
35 public:
36 
37     /**
38      * The smallest format interval allowed. Default is 1 integer digit and no
39      * fraction digits.
40      */
41     DigitInterval fMin;
42 
43     /**
44      * The largest format interval allowed. Must contain fMin.
45      *  Default is all digits.
46      */
47     DigitInterval fMax;
48 
49     /**
50      * Min and max significant digits allowed. The default is no constraints.
51      */
52     SignificantDigitInterval fSignificant;
53 
54     /**
55      * The rounding increment or zero if there is no rounding increment.
56      * Default is zero.
57      */
58     DigitList fRoundingIncrement;
59 
60     /**
61      * If set, causes round() to set status to U_FORMAT_INEXACT_ERROR if
62      * any rounding is done. Default is FALSE.
63      */
64     UBool fExactOnly;
65 
66     /**
67      * If set, causes round() to set status to U_ILLEGAL_ARGUMENT_ERROR if
68      * rounded number has more than maximum integer digits. Default is FALSE.
69      */
70     UBool fFailIfOverMax;
71 
72     /**
73      * Controls the rounding mode that initVisibleDigits uses.
74      * Default is DecimalFormat::kRoundHalfEven
75      */
76     DecimalFormat::ERoundingMode fRoundingMode;
77 
78     FixedPrecision();
79 
80     /**
81      * Returns TRUE if this object equals rhs.
82      */
equals(const FixedPrecision & rhs)83     UBool equals(const FixedPrecision &rhs) const {
84         return (fMin.equals(rhs.fMin) &&
85                 fMax.equals(rhs.fMax) &&
86                 fSignificant.equals(rhs.fSignificant) &&
87                 (fRoundingIncrement == rhs.fRoundingIncrement) &&
88                 fExactOnly == rhs.fExactOnly &&
89                 fFailIfOverMax == rhs.fFailIfOverMax &&
90                 fRoundingMode == rhs.fRoundingMode);
91     }
92 
93     /**
94      * Rounds value in place to prepare it for formatting.
95      * @param value The value to be rounded. It is rounded in place.
96      * @param exponent Always pass 0 for fixed decimal formatting. scientific
97      *  precision passes the exponent value.  Essentially, it divides value by
98      *  10^exponent, rounds and then multiplies by 10^exponent.
99      * @param status error returned here.
100      * @return reference to value.
101      */
102     DigitList &round(DigitList &value, int32_t exponent, UErrorCode &status) const;
103 
104     /**
105      * Returns the interval to use to format the rounded value.
106      * @param roundedValue the already rounded value to format.
107      * @param interval modified in place to be the interval to use to format
108      *   the rounded value.
109      * @return a reference to interval.
110      */
111     DigitInterval &getInterval(
112             const DigitList &roundedValue, DigitInterval &interval) const;
113 
114     /**
115      * Returns TRUE if this instance allows for fast formatting of integers.
116      */
117     UBool isFastFormattable() const;
118 
119     /**
120      * Initializes a VisibleDigits.
121      * @param value value for VisibleDigits
122      *    Caller must not assume that the value of this parameter will remain
123      *    unchanged.
124      * @param digits This is the value that is initialized.
125      * @param status any error returned here.
126      * @return digits
127      */
128     VisibleDigits &initVisibleDigits(
129             DigitList &value,
130             VisibleDigits &digits,
131             UErrorCode &status) const;
132 
133     /**
134      * Initializes a VisibleDigits.
135      * @param value value for VisibleDigits
136      * @param digits This is the value that is initialized.
137      * @param status any error returned here.
138      * @return digits
139      */
140     VisibleDigits &initVisibleDigits(
141             double value,
142             VisibleDigits &digits,
143             UErrorCode &status) const;
144 
145     /**
146      * Initializes a VisibleDigits.
147      * @param value value for VisibleDigits
148      * @param digits This is the value that is initialized.
149      * @param status any error returned here.
150      * @return digits
151      */
152     VisibleDigits &initVisibleDigits(
153             int64_t value,
154             VisibleDigits &digits,
155             UErrorCode &status) const;
156 
157     /**
158      * Initializes a VisibleDigitsWithExponent.
159      * @param value value for VisibleDigits
160      *    Caller must not assume that the value of this parameter will remain
161      *    unchanged.
162      * @param digits This is the value that is initialized.
163      * @param status any error returned here.
164      * @return digits
165      */
166     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
167             DigitList &value,
168             VisibleDigitsWithExponent &digits,
169             UErrorCode &status) const;
170 
171     /**
172      * Initializes a VisibleDigitsWithExponent.
173      * @param value value for VisibleDigits
174      * @param digits This is the value that is initialized.
175      * @param status any error returned here.
176      * @return digits
177      */
178     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
179             double value,
180             VisibleDigitsWithExponent &digits,
181             UErrorCode &status) const;
182 
183     /**
184      * Initializes a VisibleDigitsWithExponent.
185      * @param value value for VisibleDigits
186      * @param digits This is the value that is initialized.
187      * @param status any error returned here.
188      * @return digits
189      */
190     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
191             int64_t value,
192             VisibleDigitsWithExponent &digits,
193             UErrorCode &status) const;
194 
195 private:
196     /**
197      * Attempts to initialize 'digits' using simple mod 10 arithmetic.
198      * Returns FALSE if this is not possible such as when rounding
199      * would change the value. Otherwise returns TRUE.
200      *
201      * If the method returns FALSE, caller should create a DigitList
202      * and use it to initialize 'digits'. If this method returns TRUE,
203      * caller should accept the value stored in 'digits'. If this
204      * method returns TRUE along with a non zero error, caller must accept
205      * the error and not try again with a DigitList.
206      *
207      * Before calling this method, caller must verify that this object
208      * has no rounding increment set.
209      *
210      * The value that 'digits' is initialized to is mantissa * 10^exponent.
211      * For example mantissa = 54700 and exponent = -3 means 54.7. The
212      * properties of this object (such as min and max fraction digits),
213      * not the number of trailing zeros in the mantissa, determine whether or
214      * not the result contains any trailing 0's after the decimal point.
215      *
216      * @param mantissa the digits. May be positive or negative. May contain
217      *  trailing zeros.
218      * @param exponent must always be zero or negative. An exponent > 0
219      *  yields undefined results!
220      * @param digits result stored here.
221      * @param status any error returned here.
222      */
223     UBool
224     initVisibleDigits(
225             int64_t mantissa,
226             int32_t exponent,
227             VisibleDigits &digits,
228             UErrorCode &status) const;
229     UBool isRoundingRequired(
230             int32_t upperExponent, int32_t lowerExponent) const;
231     DigitInterval &getIntervalForZero(DigitInterval &interval) const;
232     DigitInterval &getInterval(
233             int32_t upperExponent, DigitInterval &interval) const;
234     static UBool handleNonNumeric(DigitList &value, VisibleDigits &digits);
235 
236     friend class ScientificPrecision;
237 };
238 
239 /**
240  * A precision manager for values to be expressed as scientific notation.
241  */
242 class U_I18N_API ScientificPrecision : public UMemory {
243 public:
244     FixedPrecision fMantissa;
245     int32_t fMinExponentDigits;
246 
247     ScientificPrecision();
248 
249     /**
250      * rounds value in place to prepare it for formatting.
251      * @param value The value to be rounded. It is rounded in place.
252      * @param status error returned here.
253      * @return reference to value.
254      */
255     DigitList &round(DigitList &value, UErrorCode &status) const;
256 
257     /**
258      * Converts value to a mantissa and exponent.
259      *
260      * @param value modified in place to be the mantissa. Depending on
261      *   the precision settings, the resulting mantissa may not fall
262      *   between 1.0 and 10.0.
263      * @return the exponent of value.
264      */
265     int32_t toScientific(DigitList &value) const;
266 
267     /**
268      * Returns TRUE if this object equals rhs.
269      */
equals(const ScientificPrecision & rhs)270     UBool equals(const ScientificPrecision &rhs) const {
271         return fMantissa.equals(rhs.fMantissa) && fMinExponentDigits == rhs.fMinExponentDigits;
272     }
273 
274     /**
275      * Initializes a VisibleDigitsWithExponent.
276      * @param value the value
277      *    Caller must not assume that the value of this parameter will remain
278      *    unchanged.
279      * @param digits This is the value that is initialized.
280      * @param status any error returned here.
281      * @return digits
282      */
283     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
284             DigitList &value,
285             VisibleDigitsWithExponent &digits,
286             UErrorCode &status) const;
287 
288     /**
289      * Initializes a VisibleDigitsWithExponent.
290      * @param value the value
291      * @param digits This is the value that is initialized.
292      * @param status any error returned here.
293      * @return digits
294      */
295     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
296             double value,
297             VisibleDigitsWithExponent &digits,
298             UErrorCode &status) const;
299 
300     /**
301      * Initializes a VisibleDigitsWithExponent.
302      * @param value the value
303      * @param digits This is the value that is initialized.
304      * @param status any error returned here.
305      * @return digits
306      */
307     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
308             int64_t value,
309             VisibleDigitsWithExponent &digits,
310             UErrorCode &status) const;
311 
312 private:
313     int32_t getMultiplier() const;
314 
315 };
316 
317 
318 
319 U_NAMESPACE_END
320 #endif // #if !UCONFIG_NO_FORMATTING
321 #endif  // __PRECISION_H__
322