553 lines
20 KiB
C++
553 lines
20 KiB
C++
// © 2017 and later: Unicode, Inc. and others.
|
|
// License & terms of use: http://www.unicode.org/copyright.html
|
|
|
|
#include "unicode/utypes.h"
|
|
|
|
#if !UCONFIG_NO_FORMATTING
|
|
|
|
#include "charstr.h"
|
|
#include "uassert.h"
|
|
#include "unicode/numberformatter.h"
|
|
#include "number_types.h"
|
|
#include "number_decimalquantity.h"
|
|
#include "double-conversion.h"
|
|
#include "number_roundingutils.h"
|
|
#include "number_skeletons.h"
|
|
#include "number_decnum.h"
|
|
#include "putilimp.h"
|
|
#include "string_segment.h"
|
|
|
|
using namespace icu;
|
|
using namespace icu::number;
|
|
using namespace icu::number::impl;
|
|
|
|
|
|
using double_conversion::DoubleToStringConverter;
|
|
using icu::StringSegment;
|
|
|
|
void number::impl::parseIncrementOption(const StringSegment &segment,
|
|
Precision &outPrecision,
|
|
UErrorCode &status) {
|
|
// Need to do char <-> UChar 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);
|
|
}
|
|
|
|
namespace {
|
|
|
|
int32_t getRoundingMagnitudeFraction(int maxFrac) {
|
|
if (maxFrac == -1) {
|
|
return INT32_MIN;
|
|
}
|
|
return -maxFrac;
|
|
}
|
|
|
|
int32_t getRoundingMagnitudeSignificant(const DecimalQuantity &value, int maxSig) {
|
|
if (maxSig == -1) {
|
|
return INT32_MIN;
|
|
}
|
|
int magnitude = value.isZeroish() ? 0 : value.getMagnitude();
|
|
return magnitude - maxSig + 1;
|
|
}
|
|
|
|
int32_t getDisplayMagnitudeFraction(int minFrac) {
|
|
if (minFrac == 0) {
|
|
return INT32_MAX;
|
|
}
|
|
return -minFrac;
|
|
}
|
|
|
|
int32_t getDisplayMagnitudeSignificant(const DecimalQuantity &value, int minSig) {
|
|
int magnitude = value.isZeroish() ? 0 : value.getMagnitude();
|
|
return magnitude - minSig + 1;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
MultiplierProducer::~MultiplierProducer() = default;
|
|
|
|
|
|
Precision Precision::unlimited() {
|
|
return Precision(RND_NONE, {});
|
|
}
|
|
|
|
FractionPrecision Precision::integer() {
|
|
return constructFraction(0, 0);
|
|
}
|
|
|
|
FractionPrecision Precision::fixedFraction(int32_t minMaxFractionPlaces) {
|
|
if (minMaxFractionPlaces >= 0 && minMaxFractionPlaces <= kMaxIntFracSig) {
|
|
return constructFraction(minMaxFractionPlaces, minMaxFractionPlaces);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
FractionPrecision Precision::minFraction(int32_t minFractionPlaces) {
|
|
if (minFractionPlaces >= 0 && minFractionPlaces <= kMaxIntFracSig) {
|
|
return constructFraction(minFractionPlaces, -1);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
FractionPrecision Precision::maxFraction(int32_t maxFractionPlaces) {
|
|
if (maxFractionPlaces >= 0 && maxFractionPlaces <= kMaxIntFracSig) {
|
|
return constructFraction(0, maxFractionPlaces);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
FractionPrecision Precision::minMaxFraction(int32_t minFractionPlaces, int32_t maxFractionPlaces) {
|
|
if (minFractionPlaces >= 0 && maxFractionPlaces <= kMaxIntFracSig &&
|
|
minFractionPlaces <= maxFractionPlaces) {
|
|
return constructFraction(minFractionPlaces, maxFractionPlaces);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
Precision Precision::fixedSignificantDigits(int32_t minMaxSignificantDigits) {
|
|
if (minMaxSignificantDigits >= 1 && minMaxSignificantDigits <= kMaxIntFracSig) {
|
|
return constructSignificant(minMaxSignificantDigits, minMaxSignificantDigits);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
Precision Precision::minSignificantDigits(int32_t minSignificantDigits) {
|
|
if (minSignificantDigits >= 1 && minSignificantDigits <= kMaxIntFracSig) {
|
|
return constructSignificant(minSignificantDigits, -1);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
Precision Precision::maxSignificantDigits(int32_t maxSignificantDigits) {
|
|
if (maxSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig) {
|
|
return constructSignificant(1, maxSignificantDigits);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
Precision Precision::minMaxSignificantDigits(int32_t minSignificantDigits, int32_t maxSignificantDigits) {
|
|
if (minSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig &&
|
|
minSignificantDigits <= maxSignificantDigits) {
|
|
return constructSignificant(minSignificantDigits, maxSignificantDigits);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
Precision Precision::trailingZeroDisplay(UNumberTrailingZeroDisplay trailingZeroDisplay) const {
|
|
Precision result(*this); // copy constructor
|
|
result.fTrailingZeroDisplay = trailingZeroDisplay;
|
|
return result;
|
|
}
|
|
|
|
IncrementPrecision Precision::increment(double roundingIncrement) {
|
|
if (roundingIncrement > 0.0) {
|
|
DecimalQuantity dq;
|
|
dq.setToDouble(roundingIncrement);
|
|
dq.roundToInfinity();
|
|
int32_t magnitude = dq.adjustToZeroScale();
|
|
return constructIncrement(dq.toLong(), magnitude);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
IncrementPrecision Precision::incrementExact(uint64_t mantissa, int16_t magnitude) {
|
|
if (mantissa > 0.0) {
|
|
return constructIncrement(mantissa, magnitude);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
CurrencyPrecision Precision::currency(UCurrencyUsage currencyUsage) {
|
|
return constructCurrency(currencyUsage);
|
|
}
|
|
|
|
Precision FractionPrecision::withSignificantDigits(
|
|
int32_t minSignificantDigits,
|
|
int32_t maxSignificantDigits,
|
|
UNumberRoundingPriority priority) const {
|
|
if (fType == RND_ERROR) { return *this; } // no-op in error state
|
|
if (minSignificantDigits >= 1 &&
|
|
maxSignificantDigits >= minSignificantDigits &&
|
|
maxSignificantDigits <= kMaxIntFracSig) {
|
|
return constructFractionSignificant(
|
|
*this,
|
|
minSignificantDigits,
|
|
maxSignificantDigits,
|
|
priority,
|
|
false);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
Precision FractionPrecision::withMinDigits(int32_t minSignificantDigits) const {
|
|
if (fType == RND_ERROR) { return *this; } // no-op in error state
|
|
if (minSignificantDigits >= 1 && minSignificantDigits <= kMaxIntFracSig) {
|
|
return constructFractionSignificant(
|
|
*this,
|
|
1,
|
|
minSignificantDigits,
|
|
UNUM_ROUNDING_PRIORITY_RELAXED,
|
|
true);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
Precision FractionPrecision::withMaxDigits(int32_t maxSignificantDigits) const {
|
|
if (fType == RND_ERROR) { return *this; } // no-op in error state
|
|
if (maxSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig) {
|
|
return constructFractionSignificant(*this,
|
|
1,
|
|
maxSignificantDigits,
|
|
UNUM_ROUNDING_PRIORITY_STRICT,
|
|
true);
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
// Private method on base class
|
|
Precision Precision::withCurrency(const CurrencyUnit ¤cy, UErrorCode &status) const {
|
|
if (fType == RND_ERROR) { return *this; } // no-op in error state
|
|
U_ASSERT(fType == RND_CURRENCY);
|
|
const char16_t *isoCode = currency.getISOCurrency();
|
|
double increment = ucurr_getRoundingIncrementForUsage(isoCode, fUnion.currencyUsage, &status);
|
|
int32_t minMaxFrac = ucurr_getDefaultFractionDigitsForUsage(
|
|
isoCode, fUnion.currencyUsage, &status);
|
|
Precision retval = (increment != 0.0)
|
|
? Precision::increment(increment)
|
|
: static_cast<Precision>(Precision::fixedFraction(minMaxFrac));
|
|
retval.fTrailingZeroDisplay = fTrailingZeroDisplay;
|
|
return retval;
|
|
}
|
|
|
|
// Public method on CurrencyPrecision subclass
|
|
Precision CurrencyPrecision::withCurrency(const CurrencyUnit ¤cy) const {
|
|
UErrorCode localStatus = U_ZERO_ERROR;
|
|
Precision result = Precision::withCurrency(currency, localStatus);
|
|
if (U_FAILURE(localStatus)) {
|
|
return {localStatus};
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Precision IncrementPrecision::withMinFraction(int32_t minFrac) const {
|
|
if (fType == RND_ERROR) { return *this; } // no-op in error state
|
|
if (minFrac >= 0 && minFrac <= kMaxIntFracSig) {
|
|
IncrementPrecision copy = *this;
|
|
copy.fUnion.increment.fMinFrac = minFrac;
|
|
return copy;
|
|
} else {
|
|
return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
|
|
}
|
|
}
|
|
|
|
FractionPrecision Precision::constructFraction(int32_t minFrac, int32_t maxFrac) {
|
|
FractionSignificantSettings settings;
|
|
settings.fMinFrac = static_cast<digits_t>(minFrac);
|
|
settings.fMaxFrac = static_cast<digits_t>(maxFrac);
|
|
settings.fMinSig = -1;
|
|
settings.fMaxSig = -1;
|
|
PrecisionUnion union_;
|
|
union_.fracSig = settings;
|
|
return {RND_FRACTION, union_};
|
|
}
|
|
|
|
Precision Precision::constructSignificant(int32_t minSig, int32_t maxSig) {
|
|
FractionSignificantSettings settings;
|
|
settings.fMinFrac = -1;
|
|
settings.fMaxFrac = -1;
|
|
settings.fMinSig = static_cast<digits_t>(minSig);
|
|
settings.fMaxSig = static_cast<digits_t>(maxSig);
|
|
PrecisionUnion union_;
|
|
union_.fracSig = settings;
|
|
return {RND_SIGNIFICANT, union_};
|
|
}
|
|
|
|
Precision
|
|
Precision::constructFractionSignificant(
|
|
const FractionPrecision &base,
|
|
int32_t minSig,
|
|
int32_t maxSig,
|
|
UNumberRoundingPriority priority,
|
|
bool retain) {
|
|
FractionSignificantSettings settings = base.fUnion.fracSig;
|
|
settings.fMinSig = static_cast<digits_t>(minSig);
|
|
settings.fMaxSig = static_cast<digits_t>(maxSig);
|
|
settings.fPriority = priority;
|
|
settings.fRetain = retain;
|
|
PrecisionUnion union_;
|
|
union_.fracSig = settings;
|
|
return {RND_FRACTION_SIGNIFICANT, union_};
|
|
}
|
|
|
|
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_};
|
|
} else if (increment == 5) {
|
|
return {RND_INCREMENT_FIVE, union_};
|
|
} else {
|
|
return {RND_INCREMENT, union_};
|
|
}
|
|
}
|
|
|
|
CurrencyPrecision Precision::constructCurrency(UCurrencyUsage usage) {
|
|
PrecisionUnion union_;
|
|
union_.currencyUsage = usage;
|
|
return {RND_CURRENCY, union_};
|
|
}
|
|
|
|
|
|
RoundingImpl::RoundingImpl(const Precision& precision, UNumberFormatRoundingMode roundingMode,
|
|
const CurrencyUnit& currency, UErrorCode& status)
|
|
: fPrecision(precision), fRoundingMode(roundingMode), fPassThrough(false) {
|
|
if (precision.fType == Precision::RND_CURRENCY) {
|
|
fPrecision = precision.withCurrency(currency, status);
|
|
}
|
|
}
|
|
|
|
RoundingImpl RoundingImpl::passThrough() {
|
|
return {};
|
|
}
|
|
|
|
bool RoundingImpl::isSignificantDigits() const {
|
|
return fPrecision.fType == Precision::RND_SIGNIFICANT;
|
|
}
|
|
|
|
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_FRACTION:
|
|
value.roundToMagnitude(
|
|
getRoundingMagnitudeFraction(fPrecision.fUnion.fracSig.fMaxFrac),
|
|
fRoundingMode,
|
|
status);
|
|
resolvedMinFraction =
|
|
uprv_max(0, -getDisplayMagnitudeFraction(fPrecision.fUnion.fracSig.fMinFrac));
|
|
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.setMinInteger(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;
|
|
}
|
|
}
|
|
|
|
int32_t displayMag1 = getDisplayMagnitudeFraction(fPrecision.fUnion.fracSig.fMinFrac);
|
|
int32_t displayMag2 = getDisplayMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMinSig);
|
|
int32_t displayMag;
|
|
if (fPrecision.fUnion.fracSig.fRetain) {
|
|
// withMinDigits + withMaxDigits
|
|
displayMag = uprv_min(displayMag1, displayMag2);
|
|
} else if (fPrecision.fUnion.fracSig.fPriority == UNUM_ROUNDING_PRIORITY_RELAXED) {
|
|
if (roundingMag2 <= roundingMag1) {
|
|
displayMag = displayMag2;
|
|
} else {
|
|
displayMag = displayMag1;
|
|
}
|
|
} else {
|
|
U_ASSERT(fPrecision.fUnion.fracSig.fPriority == UNUM_ROUNDING_PRIORITY_STRICT);
|
|
if (roundingMag2 <= roundingMag1) {
|
|
displayMag = displayMag1;
|
|
} else {
|
|
displayMag = displayMag2;
|
|
}
|
|
}
|
|
resolvedMinFraction = uprv_max(0, -displayMag);
|
|
|
|
break;
|
|
}
|
|
|
|
case Precision::RND_INCREMENT:
|
|
value.roundToIncrement(
|
|
fPrecision.fUnion.increment.fIncrement,
|
|
fPrecision.fUnion.increment.fIncrementMagnitude,
|
|
fRoundingMode,
|
|
status);
|
|
resolvedMinFraction = fPrecision.fUnion.increment.fMinFrac;
|
|
break;
|
|
|
|
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 */
|