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