MultiplierProducer::~MultiplierProducer() = default;
-digits_t roundingutils::doubleFractionLength(double input) {
+digits_t roundingutils::doubleFractionLength(double input, int8_t* singleDigit) {
char buffer[DoubleToStringConverter::kBase10MaximalLength + 1];
bool sign; // unused; always positive
int32_t length;
&point
);
+ if (singleDigit == nullptr) {
+ // no-op
+ } else if (length == 1) {
+ *singleDigit = buffer[0] - '0';
+ } else {
+ *singleDigit = -1;
+ }
+
return static_cast<digits_t>(length - point);
}
return constructCurrency(currencyUsage);
}
-Precision Precision::withMode(RoundingMode roundingMode) const {
- if (fType == RND_ERROR) { return *this; } // no-op in error state
- Precision retval = *this;
- retval.fRoundingMode = roundingMode;
- return retval;
-}
-
Precision FractionPrecision::withMinDigits(int32_t minSignificantDigits) const {
if (fType == RND_ERROR) { return *this; } // no-op in error state
if (minSignificantDigits >= 1 && minSignificantDigits <= kMaxIntFracSig) {
return {RND_SIGNIFICANT, union_, kDefaultMode};
}
+Precision Precision::constructIncrementSignificant(double increment, int32_t minSig, int32_t maxSig) { // Apple rdar://52538227
+ IncrementSignificantSettings settings;
+ settings.fIncrement = increment;
+ settings.fMinSig = static_cast<digits_t>(minSig);
+ settings.fMaxSig = static_cast<digits_t>(maxSig);
+ PrecisionUnion union_;
+ union_.incrSig = settings;
+ return {RND_INCREMENT_SIGNIFICANT, union_, kDefaultMode};
+}
+
Precision
Precision::constructFractionSignificant(const FractionPrecision &base, int32_t minSig, int32_t maxSig) {
FractionSignificantSettings settings = base.fUnion.fracSig;
IncrementPrecision Precision::constructIncrement(double increment, int32_t minFrac) {
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.fMinFrac = static_cast<digits_t>(minFrac);
// One of the few pre-computed quantities:
// Note: it is possible for minFrac to be more than maxFrac... (misleading)
- settings.fMaxFrac = roundingutils::doubleFractionLength(increment);
+ int8_t singleDigit;
+ settings.fMaxFrac = roundingutils::doubleFractionLength(increment, &singleDigit);
PrecisionUnion union_;
union_.increment = settings;
- return {RND_INCREMENT, union_, kDefaultMode};
+ if (singleDigit == 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_, kDefaultMode};
+ } else if (singleDigit == 5) {
+ return {RND_INCREMENT_FIVE, union_, kDefaultMode};
+ } else {
+ return {RND_INCREMENT, union_, kDefaultMode};
+ }
}
CurrencyPrecision Precision::constructCurrency(UCurrencyUsage usage) {
getRoundingMagnitudeFraction(fPrecision.fUnion.fracSig.fMaxFrac),
fRoundingMode,
status);
- value.setFractionLength(
- uprv_max(0, -getDisplayMagnitudeFraction(fPrecision.fUnion.fracSig.fMinFrac)),
- INT32_MAX);
+ value.setMinFraction(
+ uprv_max(0, -getDisplayMagnitudeFraction(fPrecision.fUnion.fracSig.fMinFrac)));
break;
case Precision::RND_SIGNIFICANT:
getRoundingMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMaxSig),
fRoundingMode,
status);
- value.setFractionLength(
- uprv_max(0, -getDisplayMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMinSig)),
- INT32_MAX);
+ value.setMinFraction(
+ uprv_max(0, -getDisplayMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMinSig)));
// Make sure that digits are displayed on zero.
if (value.isZero() && fPrecision.fUnion.fracSig.fMinSig > 0) {
- value.setIntegerLength(1, INT32_MAX);
+ value.setMinInteger(1);
}
break;
roundingMag = uprv_min(roundingMag, candidate);
}
value.roundToMagnitude(roundingMag, fRoundingMode, status);
- value.setFractionLength(uprv_max(0, -displayMag), INT32_MAX);
+ value.setMinFraction(uprv_max(0, -displayMag));
break;
}
value.roundToIncrement(
fPrecision.fUnion.increment.fIncrement,
fRoundingMode,
- fPrecision.fUnion.increment.fMaxFrac,
status);
- value.setFractionLength(fPrecision.fUnion.increment.fMinFrac, INT32_MAX);
+ value.setMinFraction(fPrecision.fUnion.increment.fMinFrac);
+ break;
+
+ case Precision::RND_INCREMENT_ONE:
+ value.roundToMagnitude(
+ -fPrecision.fUnion.increment.fMaxFrac,
+ fRoundingMode,
+ status);
+ value.setMinFraction(fPrecision.fUnion.increment.fMinFrac);
+ break;
+
+ case Precision::RND_INCREMENT_FIVE:
+ value.roundToNickel(
+ -fPrecision.fUnion.increment.fMaxFrac,
+ fRoundingMode,
+ status);
+ value.setMinFraction(fPrecision.fUnion.increment.fMinFrac);
break;
case Precision::RND_CURRENCY:
// Call .withCurrency() before .apply()!
- U_ASSERT(false);
+ UPRV_UNREACHABLE;
+
+ case Precision::RND_INCREMENT_SIGNIFICANT: // Apple addition rdar://52538227
+ // FIrst round to increment
+ value.roundToIncrement(
+ fPrecision.fUnion.incrSig.fIncrement,
+ fRoundingMode,
+ status);
+ // Then round to significant digits
+ value.roundToMagnitude(
+ getRoundingMagnitudeSignificant(value, fPrecision.fUnion.incrSig.fMaxSig),
+ fRoundingMode,
+ status);
+ value.setMinFraction(
+ uprv_max(0, -getDisplayMagnitudeSignificant(value, fPrecision.fUnion.incrSig.fMinSig)));
+ // Make sure that digits are displayed on zero.
+ if (value.isZero() && fPrecision.fUnion.incrSig.fMinSig > 0) {
+ value.setMinInteger(1);
+ }
break;
+
+ default:
+ UPRV_UNREACHABLE;
}
}
// This method is intended for the one specific purpose of helping print "00.000E0".
U_ASSERT(isSignificantDigits());
U_ASSERT(value.isZero());
- value.setFractionLength(fPrecision.fUnion.fracSig.fMinSig - minInt, INT32_MAX);
+ value.setMinFraction(fPrecision.fUnion.fracSig.fMinSig - minInt);
}
#endif /* #if !UCONFIG_NO_FORMATTING */