Esempio n. 1
0
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);
}
Esempio n. 2
0
void
DigitList::set(double source, int32_t maximumDigits, UBool fixedPoint)
{
    // for now, simple implementation; later, do proper IEEE stuff
    char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough)
    char *digitPtr      = fDigits;
    char *repPtr        = rep + 2;  // +2 to skip the sign and decimal
    int32_t exponent    = 0;

    fIsPositive = !uprv_isNegative(source);    // Allow +0 and -0

    // Generate a representation of the form /[+-][0-9]+e[+-][0-9]+/
    sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source);
    fDecimalAt  = 0;
    rep[2]      = rep[1];    // remove decimal

    while (*repPtr == kZero) {
        repPtr++;
        fDecimalAt--;   // account for leading zeros
    }

    while (*repPtr != 'e') {
        *(digitPtr++) = *(repPtr++);
    }
    fCount = MAX_DBL_DIGITS + fDecimalAt;

    // Parse an exponent of the form /[eE][+-][0-9]+/
    UBool negExp = (*(++repPtr) == '-');
    while (*(++repPtr) != 0) {
        exponent = 10*exponent + *repPtr - kZero;
    }
    if (negExp) {
        exponent = -exponent;
    }
    fDecimalAt += exponent + 1; // +1 for decimal removal

    // The negative of the exponent represents the number of leading
    // zeros between the decimal and the first non-zero digit, for
    // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2).  If this
    // is more than the maximum fraction digits, then we have an underflow
    // for the printed representation.
    if (fixedPoint && -fDecimalAt >= maximumDigits)
    {
        // If we round 0.0009 to 3 fractional digits, then we have to
        // create a new one digit in the least significant location.
        if (-fDecimalAt == maximumDigits && shouldRoundUp(0)) {
            fCount = 1;
            ++fDecimalAt;
            fDigits[0] = (char)'1';
        } else {
            // Handle an underflow to zero when we round something like
            // 0.0009 to 2 fractional digits.
            fCount = 0;
        }
        return;
    }


    // Eliminate digits beyond maximum digits to be displayed.
    // Round up if appropriate.  Do NOT round in the special
    // case where maximumDigits == 0 and fixedPoint is FALSE.
    if (fixedPoint || (0 < maximumDigits && maximumDigits < fCount)) {
        round(fixedPoint ? (maximumDigits + fDecimalAt) : maximumDigits);
    }
    else {
        // Eliminate trailing zeros.
        while (fCount > 1 && fDigits[fCount - 1] == kZero)
            --fCount;
    }
}