using double_conversion::DoubleToStringConverter; using icu::StringSegment;
void number::impl::parseIncrementOption(const StringSegment &segment,
Precision &outPrecision,
UErrorCode &status) { // Need to do char <-> char16_t conversion...
U_ASSERT(U_SUCCESS(status));
CharString buffer;
SKELETON_UCHAR_TO_CHAR(buffer, segment.toTempUnicodeString(), 0, segment.length(), status);
// Utilize DecimalQuantity/decNumber to parse this for us.
DecimalQuantity dq;
UErrorCode localStatus = U_ZERO_ERROR;
dq.setToDecNumber({buffer.data(), buffer.length()}, localStatus); if (U_FAILURE(localStatus) || dq.isNaN() || dq.isInfinite()) { // throw new SkeletonSyntaxException("Invalid rounding increment", segment, e);
status = U_NUMBER_SKELETON_SYNTAX_ERROR; return;
} // Now we break apart the number into a mantissa and exponent (magnitude).
int32_t magnitude = dq.adjustToZeroScale(); // setToDecNumber drops trailing zeros, so we search for the '.' manually. for (int32_t i=0; i<buffer.length(); i++) { if (buffer[i] == '.') {
int32_t newMagnitude = i - buffer.length() + 1;
dq.adjustMagnitude(magnitude - newMagnitude);
magnitude = newMagnitude; break;
}
}
outPrecision = Precision::incrementExact(dq.toLong(), magnitude);
}
IncrementPrecision Precision::constructIncrement(uint64_t increment, digits_t magnitude) {
IncrementSettings settings; // Note: For number formatting, fIncrement is used for RND_INCREMENT but not // RND_INCREMENT_ONE or RND_INCREMENT_FIVE. However, fIncrement is used in all // three when constructing a skeleton.
settings.fIncrement = increment;
settings.fIncrementMagnitude = magnitude;
settings.fMinFrac = magnitude > 0 ? 0 : -magnitude;
PrecisionUnion union_;
union_.increment = settings; if (increment == 1) { // NOTE: In C++, we must return the correct value type with the correct union. // It would be invalid to return a RND_FRACTION here because the methods on the // IncrementPrecision type assume that the union is backed by increment data. return {RND_INCREMENT_ONE, union_};
} elseif (increment == 5) { return {RND_INCREMENT_FIVE, union_};
} else { return {RND_INCREMENT, union_};
}
}
int32_t
RoundingImpl::chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::MultiplierProducer &producer,
UErrorCode &status) { // Do not call this method with zero, NaN, or infinity.
U_ASSERT(!input.isZeroish());
// Perform the first attempt at rounding. int magnitude = input.getMagnitude(); int multiplier = producer.getMultiplier(magnitude);
input.adjustMagnitude(multiplier);
apply(input, status);
// If the number rounded to zero, exit. if (input.isZeroish() || U_FAILURE(status)) { return multiplier;
}
// If the new magnitude after rounding is the same as it was before rounding, then we are done. // This case applies to most numbers. if (input.getMagnitude() == magnitude + multiplier) { return multiplier;
}
// If the above case DIDN'T apply, then we have a case like 99.9 -> 100 or 999.9 -> 1000: // The number rounded up to the next magnitude. Check if the multiplier changes; if it doesn't, // we do not need to make any more adjustments. int _multiplier = producer.getMultiplier(magnitude + 1); if (multiplier == _multiplier) { return multiplier;
}
// We have a case like 999.9 -> 1000, where the correct output is "1K", not "1000". // Fix the magnitude and re-apply the rounding strategy.
input.adjustMagnitude(_multiplier - multiplier);
apply(input, status); return _multiplier;
}
/** This is the method that contains the actual rounding logic. */ void RoundingImpl::apply(impl::DecimalQuantity &value, UErrorCode& status) const { if (U_FAILURE(status)) { return;
} if (fPassThrough) { return;
}
int32_t resolvedMinFraction = 0; switch (fPrecision.fType) { case Precision::RND_BOGUS: case Precision::RND_ERROR: // Errors should be caught before the apply() method is called
status = U_INTERNAL_PROGRAM_ERROR; break;
case Precision::RND_NONE:
value.roundToInfinity(); break;
case Precision::RND_SIGNIFICANT:
value.roundToMagnitude(
getRoundingMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMaxSig),
fRoundingMode,
status);
resolvedMinFraction =
uprv_max(0, -getDisplayMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMinSig)); // Make sure that digits are displayed on zero. if (value.isZeroish() && fPrecision.fUnion.fracSig.fMinSig > 0) {
value.increaseMinIntegerTo(1);
} break;
case Precision::RND_FRACTION_SIGNIFICANT: { // From ECMA-402: /* Let sResult be ToRawPrecision(...). Let fResult be ToRawFixed(...). If intlObj.[[RoundingType]] is morePrecision, then If sResult.[[RoundingMagnitude]] ≤ fResult.[[RoundingMagnitude]], then Let result be sResult. Else, Let result be fResult. Else, Assert: intlObj.[[RoundingType]] is lessPrecision. If sResult.[[RoundingMagnitude]] ≤ fResult.[[RoundingMagnitude]], then Let result be fResult. Else, Let result be sResult.
*/
int32_t roundingMag1 = getRoundingMagnitudeFraction(fPrecision.fUnion.fracSig.fMaxFrac);
int32_t roundingMag2 = getRoundingMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMaxSig);
int32_t roundingMag; if (fPrecision.fUnion.fracSig.fPriority == UNUM_ROUNDING_PRIORITY_RELAXED) {
roundingMag = uprv_min(roundingMag1, roundingMag2);
} else {
roundingMag = uprv_max(roundingMag1, roundingMag2);
} if (!value.isZeroish()) {
int32_t upperMag = value.getMagnitude();
value.roundToMagnitude(roundingMag, fRoundingMode, status); if (!value.isZeroish() && value.getMagnitude() != upperMag && roundingMag1 == roundingMag2) { // roundingMag2 needs to be the magnitude after rounding
roundingMag2 += 1;
}
}
case Precision::RND_INCREMENT_ONE:
value.roundToMagnitude(
fPrecision.fUnion.increment.fIncrementMagnitude,
fRoundingMode,
status);
resolvedMinFraction = fPrecision.fUnion.increment.fMinFrac; break;
case Precision::RND_INCREMENT_FIVE:
value.roundToNickel(
fPrecision.fUnion.increment.fIncrementMagnitude,
fRoundingMode,
status);
resolvedMinFraction = fPrecision.fUnion.increment.fMinFrac; break;
case Precision::RND_CURRENCY: // Call .withCurrency() before .apply()!
UPRV_UNREACHABLE_EXIT;
default:
UPRV_UNREACHABLE_EXIT;
}
if (fPrecision.fTrailingZeroDisplay == UNUM_TRAILING_ZERO_AUTO || // PLURAL_OPERAND_T returns fraction digits as an integer
value.getPluralOperand(PLURAL_OPERAND_T) != 0) {
value.setMinFraction(resolvedMinFraction);
}
}
void RoundingImpl::apply(impl::DecimalQuantity &value, int32_t minInt, UErrorCode /*status*/) { // This method is intended for the one specific purpose of helping print "00.000E0". // Question: Is it useful to look at trailingZeroDisplay here?
U_ASSERT(isSignificantDigits());
U_ASSERT(value.isZeroish());
value.setMinFraction(fPrecision.fUnion.fracSig.fMinSig - minInt);
}
#endif/* #if !UCONFIG_NO_FORMATTING */
Messung V0.5
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.2Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.