LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - precision.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 241 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13