| Index: source/i18n/precision.cpp
 | 
| diff --git a/source/i18n/precision.cpp b/source/i18n/precision.cpp
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..5f28391ef10783b2f7c16b19d3478b15b5c4dff3
 | 
| --- /dev/null
 | 
| +++ b/source/i18n/precision.cpp
 | 
| @@ -0,0 +1,442 @@
 | 
| +/*
 | 
| + * Copyright (C) 2015, International Business Machines
 | 
| + * Corporation and others.  All Rights Reserved.
 | 
| + *
 | 
| + * file name: precisison.cpp
 | 
| + */
 | 
| +
 | 
| +#include <math.h>
 | 
| +
 | 
| +#include "unicode/utypes.h"
 | 
| +
 | 
| +#if !UCONFIG_NO_FORMATTING
 | 
| +
 | 
| +#include "digitlst.h"
 | 
| +#include "fmtableimp.h"
 | 
| +#include "precision.h"
 | 
| +#include "putilimp.h"
 | 
| +#include "visibledigits.h"
 | 
| +
 | 
| +U_NAMESPACE_BEGIN
 | 
| +
 | 
| +static const int32_t gPower10[] = {1, 10, 100, 1000};
 | 
| +
 | 
| +FixedPrecision::FixedPrecision() 
 | 
| +        : fExactOnly(FALSE), fFailIfOverMax(FALSE), fRoundingMode(DecimalFormat::kRoundHalfEven) {
 | 
| +    fMin.setIntDigitCount(1);
 | 
| +    fMin.setFracDigitCount(0);
 | 
| +}
 | 
| +
 | 
| +UBool
 | 
| +FixedPrecision::isRoundingRequired(
 | 
| +        int32_t upperExponent, int32_t lowerExponent) const {
 | 
| +    int32_t leastSigAllowed = fMax.getLeastSignificantInclusive();
 | 
| +    int32_t maxSignificantDigits = fSignificant.getMax();
 | 
| +    int32_t roundDigit;
 | 
| +    if (maxSignificantDigits == INT32_MAX) {
 | 
| +        roundDigit = leastSigAllowed;
 | 
| +    } else {
 | 
| +        int32_t limitDigit = upperExponent - maxSignificantDigits;
 | 
| +        roundDigit =
 | 
| +                limitDigit > leastSigAllowed ? limitDigit : leastSigAllowed;
 | 
| +    }
 | 
| +    return (roundDigit > lowerExponent);
 | 
| +}
 | 
| +
 | 
| +DigitList &
 | 
| +FixedPrecision::round(
 | 
| +        DigitList &value, int32_t exponent, UErrorCode &status) const {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return value;
 | 
| +    }
 | 
| +    value .fContext.status &= ~DEC_Inexact;
 | 
| +    if (!fRoundingIncrement.isZero()) {
 | 
| +        if (exponent == 0) {
 | 
| +            value.quantize(fRoundingIncrement, status);
 | 
| +        } else {
 | 
| +            DigitList adjustedIncrement(fRoundingIncrement);
 | 
| +            adjustedIncrement.shiftDecimalRight(exponent);
 | 
| +            value.quantize(adjustedIncrement, status);
 | 
| +        }
 | 
| +        if (U_FAILURE(status)) {
 | 
| +            return value;
 | 
| +        }
 | 
| +    }
 | 
| +    int32_t leastSig = fMax.getLeastSignificantInclusive();
 | 
| +    if (leastSig == INT32_MIN) {
 | 
| +        value.round(fSignificant.getMax());
 | 
| +    } else {
 | 
| +        value.roundAtExponent(
 | 
| +                exponent + leastSig,
 | 
| +                fSignificant.getMax());
 | 
| +    }
 | 
| +    if (fExactOnly && (value.fContext.status & DEC_Inexact)) {
 | 
| +        status = U_FORMAT_INEXACT_ERROR;
 | 
| +    } else if (fFailIfOverMax) {
 | 
| +        // Smallest interval for value stored in interval
 | 
| +        DigitInterval interval;
 | 
| +        value.getSmallestInterval(interval);
 | 
| +        if (fMax.getIntDigitCount() < interval.getIntDigitCount()) {
 | 
| +            status = U_ILLEGAL_ARGUMENT_ERROR;
 | 
| +        }
 | 
| +    }
 | 
| +    return value;
 | 
| +}
 | 
| +
 | 
| +DigitInterval &
 | 
| +FixedPrecision::getIntervalForZero(DigitInterval &interval) const {
 | 
| +    interval = fMin;
 | 
| +    if (fSignificant.getMin() > 0) {
 | 
| +        interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin());
 | 
| +    }
 | 
| +    interval.shrinkToFitWithin(fMax);
 | 
| +    return interval;
 | 
| +}
 | 
| +
 | 
| +DigitInterval &
 | 
| +FixedPrecision::getInterval(
 | 
| +        int32_t upperExponent, DigitInterval &interval) const {
 | 
| +    if (fSignificant.getMin() > 0) {
 | 
| +        interval.expandToContainDigit(
 | 
| +                upperExponent - fSignificant.getMin());
 | 
| +    }
 | 
| +    interval.expandToContain(fMin);
 | 
| +    interval.shrinkToFitWithin(fMax);
 | 
| +    return interval;
 | 
| +}
 | 
| +
 | 
| +DigitInterval &
 | 
| +FixedPrecision::getInterval(
 | 
| +        const DigitList &value, DigitInterval &interval) const {
 | 
| +    if (value.isZero()) {
 | 
| +        interval = fMin;
 | 
| +        if (fSignificant.getMin() > 0) {
 | 
| +            interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin());
 | 
| +        }
 | 
| +    } else {
 | 
| +        value.getSmallestInterval(interval);
 | 
| +        if (fSignificant.getMin() > 0) {
 | 
| +            interval.expandToContainDigit(
 | 
| +                    value.getUpperExponent() - fSignificant.getMin());
 | 
| +        }
 | 
| +        interval.expandToContain(fMin);
 | 
| +    }
 | 
| +    interval.shrinkToFitWithin(fMax);
 | 
| +    return interval;
 | 
| +}
 | 
| +
 | 
| +UBool
 | 
| +FixedPrecision::isFastFormattable() const {
 | 
| +    return (fMin.getFracDigitCount() == 0 && fSignificant.isNoConstraints() && fRoundingIncrement.isZero() && !fFailIfOverMax);
 | 
| +}
 | 
| +
 | 
| +UBool
 | 
| +FixedPrecision::handleNonNumeric(DigitList &value, VisibleDigits &digits) {
 | 
| +    if (value.isNaN()) {
 | 
| +        digits.setNaN();
 | 
| +        return TRUE;
 | 
| +    }
 | 
| +    if (value.isInfinite()) {
 | 
| +        digits.setInfinite();
 | 
| +        if (!value.isPositive()) {
 | 
| +            digits.setNegative();
 | 
| +        }
 | 
| +        return TRUE;
 | 
| +    }
 | 
| +    return FALSE;
 | 
| +}
 | 
| +
 | 
| +VisibleDigits &
 | 
| +FixedPrecision::initVisibleDigits(
 | 
| +        DigitList &value,
 | 
| +        VisibleDigits &digits,
 | 
| +        UErrorCode &status) const {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return digits;
 | 
| +    }
 | 
| +    digits.clear();
 | 
| +    if (handleNonNumeric(value, digits)) {
 | 
| +        return digits;
 | 
| +    }
 | 
| +    if (!value.isPositive()) {
 | 
| +        digits.setNegative();
 | 
| +    }
 | 
| +    value.setRoundingMode(fRoundingMode);
 | 
| +    round(value, 0, status);
 | 
| +    getInterval(value, digits.fInterval);
 | 
| +    digits.fExponent = value.getLowerExponent();
 | 
| +    value.appendDigitsTo(digits.fDigits, status);
 | 
| +    return digits;
 | 
| +}
 | 
| +
 | 
| +VisibleDigits &
 | 
| +FixedPrecision::initVisibleDigits(
 | 
| +        int64_t value,
 | 
| +        VisibleDigits &digits,
 | 
| +        UErrorCode &status) const {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return digits;
 | 
| +    }
 | 
| +    if (!fRoundingIncrement.isZero()) {
 | 
| +        // If we have round increment, use digit list.
 | 
| +        DigitList digitList;
 | 
| +        digitList.set(value);
 | 
| +        return initVisibleDigits(digitList, digits, status);
 | 
| +    }
 | 
| +    // Try fast path
 | 
| +    if (initVisibleDigits(value, 0, digits, status)) {
 | 
| +        digits.fAbsDoubleValue = fabs((double) value);
 | 
| +        digits.fAbsDoubleValueSet = U_SUCCESS(status) && !digits.isOverMaxDigits();
 | 
| +        return digits;
 | 
| +    }
 | 
| +    // Oops have to use digit list
 | 
| +    DigitList digitList;
 | 
| +    digitList.set(value);
 | 
| +    return initVisibleDigits(digitList, digits, status);
 | 
| +}
 | 
| +
 | 
| +VisibleDigits &
 | 
| +FixedPrecision::initVisibleDigits(
 | 
| +        double value,
 | 
| +        VisibleDigits &digits,
 | 
| +        UErrorCode &status) const {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return digits;
 | 
| +    }
 | 
| +    digits.clear();
 | 
| +    if (uprv_isNaN(value)) {
 | 
| +        digits.setNaN();
 | 
| +        return digits;
 | 
| +    }
 | 
| +    if (uprv_isPositiveInfinity(value)) {
 | 
| +        digits.setInfinite();
 | 
| +        return digits;
 | 
| +    }
 | 
| +    if (uprv_isNegativeInfinity(value)) {
 | 
| +        digits.setInfinite();
 | 
| +        digits.setNegative();
 | 
| +        return digits;
 | 
| +    }
 | 
| +    if (!fRoundingIncrement.isZero()) {
 | 
| +        // If we have round increment, use digit list.
 | 
| +        DigitList digitList;
 | 
| +        digitList.set(value);
 | 
| +        return initVisibleDigits(digitList, digits, status);
 | 
| +    }
 | 
| +    // Try to find n such that value * 10^n is an integer
 | 
| +    int32_t n = -1;
 | 
| +    double scaled;
 | 
| +    for (int32_t i = 0; i < UPRV_LENGTHOF(gPower10); ++i) {
 | 
| +        scaled = value * gPower10[i];
 | 
| +        if (scaled > MAX_INT64_IN_DOUBLE || scaled < -MAX_INT64_IN_DOUBLE) {
 | 
| +            break;
 | 
| +        }
 | 
| +        if (scaled == floor(scaled)) {
 | 
| +            n = i;
 | 
| +            break;
 | 
| +        }
 | 
| +    }
 | 
| +    // Try fast path
 | 
| +    if (n >= 0 && initVisibleDigits(scaled, -n, digits, status)) {
 | 
| +        digits.fAbsDoubleValue = fabs(value);
 | 
| +        digits.fAbsDoubleValueSet = U_SUCCESS(status) && !digits.isOverMaxDigits();
 | 
| +        // Adjust for negative 0 becuase when we cast to an int64,
 | 
| +        // negative 0 becomes positive 0.
 | 
| +        if (scaled == 0.0 && uprv_isNegative(scaled)) {
 | 
| +            digits.setNegative();
 | 
| +        }
 | 
| +        return digits;
 | 
| +    }
 | 
| +
 | 
| +    // Oops have to use digit list
 | 
| +    DigitList digitList;
 | 
| +    digitList.set(value);
 | 
| +    return initVisibleDigits(digitList, digits, status);
 | 
| +}
 | 
| +
 | 
| +UBool
 | 
| +FixedPrecision::initVisibleDigits(
 | 
| +        int64_t mantissa,
 | 
| +        int32_t exponent,
 | 
| +        VisibleDigits &digits,
 | 
| +        UErrorCode &status) const {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return TRUE;
 | 
| +    }
 | 
| +    digits.clear();
 | 
| +
 | 
| +    // Precompute fAbsIntValue if it is small enough, but we don't know yet
 | 
| +    // if it will be valid.
 | 
| +    UBool absIntValueComputed = FALSE;
 | 
| +    if (mantissa > -1000000000000000000LL /* -1e18 */
 | 
| +            && mantissa < 1000000000000000000LL /* 1e18 */) {
 | 
| +        digits.fAbsIntValue = mantissa;
 | 
| +        if (digits.fAbsIntValue < 0) {
 | 
| +            digits.fAbsIntValue = -digits.fAbsIntValue;
 | 
| +        }
 | 
| +        int32_t i = 0;
 | 
| +        int32_t maxPower10Exp = UPRV_LENGTHOF(gPower10) - 1;
 | 
| +        for (; i > exponent + maxPower10Exp; i -= maxPower10Exp) {
 | 
| +            digits.fAbsIntValue /= gPower10[maxPower10Exp];
 | 
| +        }
 | 
| +        digits.fAbsIntValue /= gPower10[i - exponent];
 | 
| +        absIntValueComputed = TRUE;
 | 
| +    }
 | 
| +    if (mantissa == 0) {
 | 
| +        getIntervalForZero(digits.fInterval);
 | 
| +        digits.fAbsIntValueSet = absIntValueComputed;
 | 
| +        return TRUE;
 | 
| +    }
 | 
| +    // be sure least significant digit is non zero
 | 
| +    while (mantissa % 10 == 0) {
 | 
| +        mantissa /= 10;
 | 
| +        ++exponent;
 | 
| +    }
 | 
| +    if (mantissa < 0) {
 | 
| +        digits.fDigits.append((char) -(mantissa % -10), status);
 | 
| +        mantissa /= -10;
 | 
| +        digits.setNegative();
 | 
| +    }
 | 
| +    while (mantissa) {
 | 
| +        digits.fDigits.append((char) (mantissa % 10), status);
 | 
| +        mantissa /= 10;
 | 
| +    }
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return TRUE;
 | 
| +    }
 | 
| +    digits.fExponent = exponent;
 | 
| +    int32_t upperExponent = exponent + digits.fDigits.length();
 | 
| +    if (fFailIfOverMax && upperExponent > fMax.getIntDigitCount()) {
 | 
| +        status = U_ILLEGAL_ARGUMENT_ERROR;
 | 
| +        return TRUE;
 | 
| +    }
 | 
| +    UBool roundingRequired =
 | 
| +            isRoundingRequired(upperExponent, exponent);
 | 
| +    if (roundingRequired) {
 | 
| +        if (fExactOnly) {
 | 
| +            status = U_FORMAT_INEXACT_ERROR;
 | 
| +            return TRUE;
 | 
| +        }
 | 
| +        return FALSE;
 | 
| +    }
 | 
| +    digits.fInterval.setLeastSignificantInclusive(exponent);
 | 
| +    digits.fInterval.setMostSignificantExclusive(upperExponent);
 | 
| +    getInterval(upperExponent, digits.fInterval);
 | 
| +
 | 
| +    // The intValue we computed above is only valid if our visible digits
 | 
| +    // doesn't exceed the maximum integer digits allowed.
 | 
| +    digits.fAbsIntValueSet = absIntValueComputed && !digits.isOverMaxDigits();
 | 
| +    return TRUE;
 | 
| +}
 | 
| +
 | 
| +VisibleDigitsWithExponent &
 | 
| +FixedPrecision::initVisibleDigitsWithExponent(
 | 
| +        DigitList &value,
 | 
| +        VisibleDigitsWithExponent &digits,
 | 
| +        UErrorCode &status) const {
 | 
| +    digits.clear();
 | 
| +    initVisibleDigits(value, digits.fMantissa, status);
 | 
| +    return digits;
 | 
| +}
 | 
| +
 | 
| +VisibleDigitsWithExponent &
 | 
| +FixedPrecision::initVisibleDigitsWithExponent(
 | 
| +        double value,
 | 
| +        VisibleDigitsWithExponent &digits,
 | 
| +        UErrorCode &status) const {
 | 
| +    digits.clear();
 | 
| +    initVisibleDigits(value, digits.fMantissa, status);
 | 
| +    return digits;
 | 
| +}
 | 
| +
 | 
| +VisibleDigitsWithExponent &
 | 
| +FixedPrecision::initVisibleDigitsWithExponent(
 | 
| +        int64_t value,
 | 
| +        VisibleDigitsWithExponent &digits,
 | 
| +        UErrorCode &status) const {
 | 
| +    digits.clear();
 | 
| +    initVisibleDigits(value, digits.fMantissa, status);
 | 
| +    return digits;
 | 
| +}
 | 
| +
 | 
| +ScientificPrecision::ScientificPrecision() : fMinExponentDigits(1) {
 | 
| +}
 | 
| +
 | 
| +DigitList &
 | 
| +ScientificPrecision::round(DigitList &value, UErrorCode &status) const {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return value;
 | 
| +    }
 | 
| +    int32_t exponent = value.getScientificExponent(
 | 
| +            fMantissa.fMin.getIntDigitCount(), getMultiplier());
 | 
| +    return fMantissa.round(value, exponent, status);
 | 
| +}
 | 
| +
 | 
| +int32_t
 | 
| +ScientificPrecision::toScientific(DigitList &value) const {
 | 
| +    return value.toScientific(
 | 
| +            fMantissa.fMin.getIntDigitCount(), getMultiplier());
 | 
| +}
 | 
| +
 | 
| +int32_t
 | 
| +ScientificPrecision::getMultiplier() const {
 | 
| +    int32_t maxIntDigitCount = fMantissa.fMax.getIntDigitCount();
 | 
| +    if (maxIntDigitCount == INT32_MAX) {
 | 
| +        return 1;
 | 
| +    }
 | 
| +    int32_t multiplier =
 | 
| +        maxIntDigitCount - fMantissa.fMin.getIntDigitCount() + 1;
 | 
| +    return (multiplier < 1 ? 1 : multiplier);
 | 
| +}
 | 
| +
 | 
| +VisibleDigitsWithExponent &
 | 
| +ScientificPrecision::initVisibleDigitsWithExponent(
 | 
| +        DigitList &value,
 | 
| +        VisibleDigitsWithExponent &digits,
 | 
| +        UErrorCode &status) const {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return digits;
 | 
| +    }
 | 
| +    digits.clear();
 | 
| +    if (FixedPrecision::handleNonNumeric(value, digits.fMantissa)) {
 | 
| +        return digits;
 | 
| +    }
 | 
| +    value.setRoundingMode(fMantissa.fRoundingMode);
 | 
| +    int64_t exponent = toScientific(round(value, status));
 | 
| +    fMantissa.initVisibleDigits(value, digits.fMantissa, status);
 | 
| +    FixedPrecision exponentPrecision;
 | 
| +    exponentPrecision.fMin.setIntDigitCount(fMinExponentDigits);
 | 
| +    exponentPrecision.initVisibleDigits(exponent, digits.fExponent, status);
 | 
| +    digits.fHasExponent = TRUE;
 | 
| +    return digits;
 | 
| +}
 | 
| +
 | 
| +VisibleDigitsWithExponent &
 | 
| +ScientificPrecision::initVisibleDigitsWithExponent(
 | 
| +        double value,
 | 
| +        VisibleDigitsWithExponent &digits,
 | 
| +        UErrorCode &status) const {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return digits;
 | 
| +    }
 | 
| +    DigitList digitList;
 | 
| +    digitList.set(value);
 | 
| +    return initVisibleDigitsWithExponent(digitList, digits, status);
 | 
| +}
 | 
| +
 | 
| +VisibleDigitsWithExponent &
 | 
| +ScientificPrecision::initVisibleDigitsWithExponent(
 | 
| +        int64_t value,
 | 
| +        VisibleDigitsWithExponent &digits,
 | 
| +        UErrorCode &status) const {
 | 
| +    if (U_FAILURE(status)) {
 | 
| +        return digits;
 | 
| +    }
 | 
| +    DigitList digitList;
 | 
| +    digitList.set(value);
 | 
| +    return initVisibleDigitsWithExponent(digitList, digits, status);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +U_NAMESPACE_END
 | 
| +#endif /* #if !UCONFIG_NO_FORMATTING */
 | 
| 
 |