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