1/* 2 * Copyright (C) 2015, International Business Machines 3 * Corporation and others. All Rights Reserved. 4 * 5 * file name: precisison.cpp 6 */ 7 8#include <math.h> 9 10#include "unicode/utypes.h" 11 12#if !UCONFIG_NO_FORMATTING 13 14#include "digitlst.h" 15#include "fmtableimp.h" 16#include "precision.h" 17#include "putilimp.h" 18#include "visibledigits.h" 19 20U_NAMESPACE_BEGIN 21 22static const int32_t gPower10[] = {1, 10, 100, 1000}; 23 24FixedPrecision::FixedPrecision() 25 : fExactOnly(FALSE), fFailIfOverMax(FALSE), fRoundingMode(DecimalFormat::kRoundHalfEven) { 26 fMin.setIntDigitCount(1); 27 fMin.setFracDigitCount(0); 28} 29 30UBool 31FixedPrecision::isRoundingRequired( 32 int32_t upperExponent, int32_t lowerExponent) const { 33 int32_t leastSigAllowed = fMax.getLeastSignificantInclusive(); 34 int32_t maxSignificantDigits = fSignificant.getMax(); 35 int32_t roundDigit; 36 if (maxSignificantDigits == INT32_MAX) { 37 roundDigit = leastSigAllowed; 38 } else { 39 int32_t limitDigit = upperExponent - maxSignificantDigits; 40 roundDigit = 41 limitDigit > leastSigAllowed ? limitDigit : leastSigAllowed; 42 } 43 return (roundDigit > lowerExponent); 44} 45 46DigitList & 47FixedPrecision::round( 48 DigitList &value, int32_t exponent, UErrorCode &status) const { 49 if (U_FAILURE(status)) { 50 return value; 51 } 52 value .fContext.status &= ~DEC_Inexact; 53 if (!fRoundingIncrement.isZero()) { 54 if (exponent == 0) { 55 value.quantize(fRoundingIncrement, status); 56 } else { 57 DigitList adjustedIncrement(fRoundingIncrement); 58 adjustedIncrement.shiftDecimalRight(exponent); 59 value.quantize(adjustedIncrement, status); 60 } 61 if (U_FAILURE(status)) { 62 return value; 63 } 64 } 65 int32_t leastSig = fMax.getLeastSignificantInclusive(); 66 if (leastSig == INT32_MIN) { 67 value.round(fSignificant.getMax()); 68 } else { 69 value.roundAtExponent( 70 exponent + leastSig, 71 fSignificant.getMax()); 72 } 73 if (fExactOnly && (value.fContext.status & DEC_Inexact)) { 74 status = U_FORMAT_INEXACT_ERROR; 75 } else if (fFailIfOverMax) { 76 // Smallest interval for value stored in interval 77 DigitInterval interval; 78 value.getSmallestInterval(interval); 79 if (fMax.getIntDigitCount() < interval.getIntDigitCount()) { 80 status = U_ILLEGAL_ARGUMENT_ERROR; 81 } 82 } 83 return value; 84} 85 86DigitInterval & 87FixedPrecision::getIntervalForZero(DigitInterval &interval) const { 88 interval = fMin; 89 if (fSignificant.getMin() > 0) { 90 interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin()); 91 } 92 interval.shrinkToFitWithin(fMax); 93 return interval; 94} 95 96DigitInterval & 97FixedPrecision::getInterval( 98 int32_t upperExponent, DigitInterval &interval) const { 99 if (fSignificant.getMin() > 0) { 100 interval.expandToContainDigit( 101 upperExponent - fSignificant.getMin()); 102 } 103 interval.expandToContain(fMin); 104 interval.shrinkToFitWithin(fMax); 105 return interval; 106} 107 108DigitInterval & 109FixedPrecision::getInterval( 110 const DigitList &value, DigitInterval &interval) const { 111 if (value.isZero()) { 112 interval = fMin; 113 if (fSignificant.getMin() > 0) { 114 interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin()); 115 } 116 } else { 117 value.getSmallestInterval(interval); 118 if (fSignificant.getMin() > 0) { 119 interval.expandToContainDigit( 120 value.getUpperExponent() - fSignificant.getMin()); 121 } 122 interval.expandToContain(fMin); 123 } 124 interval.shrinkToFitWithin(fMax); 125 return interval; 126} 127 128UBool 129FixedPrecision::isFastFormattable() const { 130 return (fMin.getFracDigitCount() == 0 && fSignificant.isNoConstraints() && fRoundingIncrement.isZero() && !fFailIfOverMax); 131} 132 133UBool 134FixedPrecision::handleNonNumeric(DigitList &value, VisibleDigits &digits) { 135 if (value.isNaN()) { 136 digits.setNaN(); 137 return TRUE; 138 } 139 if (value.isInfinite()) { 140 digits.setInfinite(); 141 if (!value.isPositive()) { 142 digits.setNegative(); 143 } 144 return TRUE; 145 } 146 return FALSE; 147} 148 149VisibleDigits & 150FixedPrecision::initVisibleDigits( 151 DigitList &value, 152 VisibleDigits &digits, 153 UErrorCode &status) const { 154 if (U_FAILURE(status)) { 155 return digits; 156 } 157 digits.clear(); 158 if (handleNonNumeric(value, digits)) { 159 return digits; 160 } 161 if (!value.isPositive()) { 162 digits.setNegative(); 163 } 164 value.setRoundingMode(fRoundingMode); 165 round(value, 0, status); 166 getInterval(value, digits.fInterval); 167 digits.fExponent = value.getLowerExponent(); 168 value.appendDigitsTo(digits.fDigits, status); 169 return digits; 170} 171 172VisibleDigits & 173FixedPrecision::initVisibleDigits( 174 int64_t value, 175 VisibleDigits &digits, 176 UErrorCode &status) const { 177 if (U_FAILURE(status)) { 178 return digits; 179 } 180 if (!fRoundingIncrement.isZero()) { 181 // If we have round increment, use digit list. 182 DigitList digitList; 183 digitList.set(value); 184 return initVisibleDigits(digitList, digits, status); 185 } 186 // Try fast path 187 if (initVisibleDigits(value, 0, digits, status)) { 188 digits.fAbsDoubleValue = fabs((double) value); 189 digits.fAbsDoubleValueSet = U_SUCCESS(status) && !digits.isOverMaxDigits(); 190 return digits; 191 } 192 // Oops have to use digit list 193 DigitList digitList; 194 digitList.set(value); 195 return initVisibleDigits(digitList, digits, status); 196} 197 198VisibleDigits & 199FixedPrecision::initVisibleDigits( 200 double value, 201 VisibleDigits &digits, 202 UErrorCode &status) const { 203 if (U_FAILURE(status)) { 204 return digits; 205 } 206 digits.clear(); 207 if (uprv_isNaN(value)) { 208 digits.setNaN(); 209 return digits; 210 } 211 if (uprv_isPositiveInfinity(value)) { 212 digits.setInfinite(); 213 return digits; 214 } 215 if (uprv_isNegativeInfinity(value)) { 216 digits.setInfinite(); 217 digits.setNegative(); 218 return digits; 219 } 220 if (!fRoundingIncrement.isZero()) { 221 // If we have round increment, use digit list. 222 DigitList digitList; 223 digitList.set(value); 224 return initVisibleDigits(digitList, digits, status); 225 } 226 // Try to find n such that value * 10^n is an integer 227 int32_t n = -1; 228 double scaled; 229 for (int32_t i = 0; i < UPRV_LENGTHOF(gPower10); ++i) { 230 scaled = value * gPower10[i]; 231 if (scaled > MAX_INT64_IN_DOUBLE || scaled < -MAX_INT64_IN_DOUBLE) { 232 break; 233 } 234 if (scaled == floor(scaled)) { 235 n = i; 236 break; 237 } 238 } 239 // Try fast path 240 if (n >= 0 && initVisibleDigits(scaled, -n, digits, status)) { 241 digits.fAbsDoubleValue = fabs(value); 242 digits.fAbsDoubleValueSet = U_SUCCESS(status) && !digits.isOverMaxDigits(); 243 // Adjust for negative 0 becuase when we cast to an int64, 244 // negative 0 becomes positive 0. 245 if (scaled == 0.0 && uprv_isNegative(scaled)) { 246 digits.setNegative(); 247 } 248 return digits; 249 } 250 251 // Oops have to use digit list 252 DigitList digitList; 253 digitList.set(value); 254 return initVisibleDigits(digitList, digits, status); 255} 256 257UBool 258FixedPrecision::initVisibleDigits( 259 int64_t mantissa, 260 int32_t exponent, 261 VisibleDigits &digits, 262 UErrorCode &status) const { 263 if (U_FAILURE(status)) { 264 return TRUE; 265 } 266 digits.clear(); 267 268 // Precompute fAbsIntValue if it is small enough, but we don't know yet 269 // if it will be valid. 270 UBool absIntValueComputed = FALSE; 271 if (mantissa > -1000000000000000000LL /* -1e18 */ 272 && mantissa < 1000000000000000000LL /* 1e18 */) { 273 digits.fAbsIntValue = mantissa; 274 if (digits.fAbsIntValue < 0) { 275 digits.fAbsIntValue = -digits.fAbsIntValue; 276 } 277 int32_t i = 0; 278 int32_t maxPower10Exp = UPRV_LENGTHOF(gPower10) - 1; 279 for (; i > exponent + maxPower10Exp; i -= maxPower10Exp) { 280 digits.fAbsIntValue /= gPower10[maxPower10Exp]; 281 } 282 digits.fAbsIntValue /= gPower10[i - exponent]; 283 absIntValueComputed = TRUE; 284 } 285 if (mantissa == 0) { 286 getIntervalForZero(digits.fInterval); 287 digits.fAbsIntValueSet = absIntValueComputed; 288 return TRUE; 289 } 290 // be sure least significant digit is non zero 291 while (mantissa % 10 == 0) { 292 mantissa /= 10; 293 ++exponent; 294 } 295 if (mantissa < 0) { 296 digits.fDigits.append((char) -(mantissa % -10), status); 297 mantissa /= -10; 298 digits.setNegative(); 299 } 300 while (mantissa) { 301 digits.fDigits.append((char) (mantissa % 10), status); 302 mantissa /= 10; 303 } 304 if (U_FAILURE(status)) { 305 return TRUE; 306 } 307 digits.fExponent = exponent; 308 int32_t upperExponent = exponent + digits.fDigits.length(); 309 if (fFailIfOverMax && upperExponent > fMax.getIntDigitCount()) { 310 status = U_ILLEGAL_ARGUMENT_ERROR; 311 return TRUE; 312 } 313 UBool roundingRequired = 314 isRoundingRequired(upperExponent, exponent); 315 if (roundingRequired) { 316 if (fExactOnly) { 317 status = U_FORMAT_INEXACT_ERROR; 318 return TRUE; 319 } 320 return FALSE; 321 } 322 digits.fInterval.setLeastSignificantInclusive(exponent); 323 digits.fInterval.setMostSignificantExclusive(upperExponent); 324 getInterval(upperExponent, digits.fInterval); 325 326 // The intValue we computed above is only valid if our visible digits 327 // doesn't exceed the maximum integer digits allowed. 328 digits.fAbsIntValueSet = absIntValueComputed && !digits.isOverMaxDigits(); 329 return TRUE; 330} 331 332VisibleDigitsWithExponent & 333FixedPrecision::initVisibleDigitsWithExponent( 334 DigitList &value, 335 VisibleDigitsWithExponent &digits, 336 UErrorCode &status) const { 337 digits.clear(); 338 initVisibleDigits(value, digits.fMantissa, status); 339 return digits; 340} 341 342VisibleDigitsWithExponent & 343FixedPrecision::initVisibleDigitsWithExponent( 344 double value, 345 VisibleDigitsWithExponent &digits, 346 UErrorCode &status) const { 347 digits.clear(); 348 initVisibleDigits(value, digits.fMantissa, status); 349 return digits; 350} 351 352VisibleDigitsWithExponent & 353FixedPrecision::initVisibleDigitsWithExponent( 354 int64_t value, 355 VisibleDigitsWithExponent &digits, 356 UErrorCode &status) const { 357 digits.clear(); 358 initVisibleDigits(value, digits.fMantissa, status); 359 return digits; 360} 361 362ScientificPrecision::ScientificPrecision() : fMinExponentDigits(1) { 363} 364 365DigitList & 366ScientificPrecision::round(DigitList &value, UErrorCode &status) const { 367 if (U_FAILURE(status)) { 368 return value; 369 } 370 int32_t exponent = value.getScientificExponent( 371 fMantissa.fMin.getIntDigitCount(), getMultiplier()); 372 return fMantissa.round(value, exponent, status); 373} 374 375int32_t 376ScientificPrecision::toScientific(DigitList &value) const { 377 return value.toScientific( 378 fMantissa.fMin.getIntDigitCount(), getMultiplier()); 379} 380 381int32_t 382ScientificPrecision::getMultiplier() const { 383 int32_t maxIntDigitCount = fMantissa.fMax.getIntDigitCount(); 384 if (maxIntDigitCount == INT32_MAX) { 385 return 1; 386 } 387 int32_t multiplier = 388 maxIntDigitCount - fMantissa.fMin.getIntDigitCount() + 1; 389 return (multiplier < 1 ? 1 : multiplier); 390} 391 392VisibleDigitsWithExponent & 393ScientificPrecision::initVisibleDigitsWithExponent( 394 DigitList &value, 395 VisibleDigitsWithExponent &digits, 396 UErrorCode &status) const { 397 if (U_FAILURE(status)) { 398 return digits; 399 } 400 digits.clear(); 401 if (FixedPrecision::handleNonNumeric(value, digits.fMantissa)) { 402 return digits; 403 } 404 value.setRoundingMode(fMantissa.fRoundingMode); 405 int64_t exponent = toScientific(round(value, status)); 406 fMantissa.initVisibleDigits(value, digits.fMantissa, status); 407 FixedPrecision exponentPrecision; 408 exponentPrecision.fMin.setIntDigitCount(fMinExponentDigits); 409 exponentPrecision.initVisibleDigits(exponent, digits.fExponent, status); 410 digits.fHasExponent = TRUE; 411 return digits; 412} 413 414VisibleDigitsWithExponent & 415ScientificPrecision::initVisibleDigitsWithExponent( 416 double value, 417 VisibleDigitsWithExponent &digits, 418 UErrorCode &status) const { 419 if (U_FAILURE(status)) { 420 return digits; 421 } 422 DigitList digitList; 423 digitList.set(value); 424 return initVisibleDigitsWithExponent(digitList, digits, status); 425} 426 427VisibleDigitsWithExponent & 428ScientificPrecision::initVisibleDigitsWithExponent( 429 int64_t value, 430 VisibleDigitsWithExponent &digits, 431 UErrorCode &status) const { 432 if (U_FAILURE(status)) { 433 return digits; 434 } 435 DigitList digitList; 436 digitList.set(value); 437 return initVisibleDigitsWithExponent(digitList, digits, status); 438} 439 440 441U_NAMESPACE_END 442#endif /* #if !UCONFIG_NO_FORMATTING */ 443