blob: 1a286cf6a8623b9a8b535ac78bc3f32019960f8e [file] [log] [blame]
/* GENERATED SOURCE. DO NOT MODIFY. */
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
package android.icu.impl.number;
import java.math.MathContext;
import java.math.RoundingMode;
import android.icu.impl.number.formatters.CompactDecimalFormat;
import android.icu.impl.number.formatters.ScientificFormat;
/**
* The base class for a Rounder used by ICU Decimal Format.
*
* <p>A Rounder must implement the method {@link #apply}. An implementation must:
*
* <ol>
* <li>Either have the code <code>applyDefaults(input);</code> in its apply function, or otherwise
* ensure that minFrac, maxFrac, minInt, and maxInt are obeyed, paying special attention to
* the case when the input is zero.
* <li>Call one of {@link FormatQuantity#roundToIncrement}, {@link
* FormatQuantity#roundToMagnitude}, or {@link FormatQuantity#roundToInfinity} on the input.
* </ol>
*
* <p>In order to be used by {@link CompactDecimalFormat} and {@link ScientificFormat}, among
* others, your rounder must be stable upon <em>decreasing</em> the magnitude of the input number.
* For example, if your rounder converts "999" to "1000", it must also convert "99.9" to "100" and
* "0.999" to "1". (The opposite does not need to be the case: you can round "0.999" to "1" but keep
* "999" as "999".)
*
* @see android.icu.impl.number.rounders.MagnitudeRounder
* @see android.icu.impl.number.rounders.IncrementRounder
* @see android.icu.impl.number.rounders.SignificantDigitsRounder
* @see android.icu.impl.number.rounders.NoRounder
* @hide Only a subset of ICU is exposed in Android
*/
public abstract class Rounder extends Format.BeforeFormat {
public static interface IBasicRoundingProperties {
static int DEFAULT_MINIMUM_INTEGER_DIGITS = -1;
/** @see #setMinimumIntegerDigits */
public int getMinimumIntegerDigits();
/**
* Sets the minimum number of digits to display before the decimal point. If the number has
* fewer than this number of digits, the number will be padded with zeros. The pattern "#00.0#",
* for example, corresponds to 2 minimum integer digits, and the number 5.3 would be formatted
* as "05.3" in locale <em>en-US</em>.
*
* @param minimumIntegerDigits The minimum number of integer digits to output.
* @return The property bag, for chaining.
*/
public IBasicRoundingProperties setMinimumIntegerDigits(int minimumIntegerDigits);
static int DEFAULT_MAXIMUM_INTEGER_DIGITS = -1;
/** @see #setMaximumIntegerDigits */
public int getMaximumIntegerDigits();
/**
* Sets the maximum number of digits to display before the decimal point. If the number has more
* than this number of digits, the extra digits will be truncated. For example, if maximum
* integer digits is 2, and you attempt to format the number 1970, you will get "70" in locale
* <em>en-US</em>. It is not possible to specify the maximum integer digits using a pattern
* string, except in the special case of a scientific format pattern.
*
* @param maximumIntegerDigits The maximum number of integer digits to output.
* @return The property bag, for chaining.
*/
public IBasicRoundingProperties setMaximumIntegerDigits(int maximumIntegerDigits);
static int DEFAULT_MINIMUM_FRACTION_DIGITS = -1;
/** @see #setMinimumFractionDigits */
public int getMinimumFractionDigits();
/**
* Sets the minimum number of digits to display after the decimal point. If the number has fewer
* than this number of digits, the number will be padded with zeros. The pattern "#00.0#", for
* example, corresponds to 1 minimum fraction digit, and the number 456 would be formatted as
* "456.0" in locale <em>en-US</em>.
*
* @param minimumFractionDigits The minimum number of fraction digits to output.
* @return The property bag, for chaining.
*/
public IBasicRoundingProperties setMinimumFractionDigits(int minimumFractionDigits);
static int DEFAULT_MAXIMUM_FRACTION_DIGITS = -1;
/** @see #setMaximumFractionDigits */
public int getMaximumFractionDigits();
/**
* Sets the maximum number of digits to display after the decimal point. If the number has fewer
* than this number of digits, the number will be rounded off using the rounding mode specified
* by {@link #setRoundingMode(RoundingMode)}. The pattern "#00.0#", for example, corresponds to
* 2 maximum fraction digits, and the number 456.789 would be formatted as "456.79" in locale
* <em>en-US</em> with the default rounding mode. Note that the number 456.999 would be
* formatted as "457.0" given the same configurations.
*
* @param maximumFractionDigits The maximum number of fraction digits to output.
* @return The property bag, for chaining.
*/
public IBasicRoundingProperties setMaximumFractionDigits(int maximumFractionDigits);
static RoundingMode DEFAULT_ROUNDING_MODE = null;
/** @see #setRoundingMode */
public RoundingMode getRoundingMode();
/**
* Sets the rounding mode, which determines under which conditions extra decimal places are
* rounded either up or down. See {@link RoundingMode} for details on the choices of rounding
* mode. The default if not set explicitly is {@link RoundingMode#HALF_EVEN}.
*
* <p>This setting is ignored if {@link #setMathContext} is used.
*
* @param roundingMode The rounding mode to use when rounding is required.
* @return The property bag, for chaining.
* @see RoundingMode
* @see #setMathContext
*/
public IBasicRoundingProperties setRoundingMode(RoundingMode roundingMode);
static MathContext DEFAULT_MATH_CONTEXT = null;
/** @see #setMathContext */
public MathContext getMathContext();
/**
* Sets the {@link MathContext} to be used during math and rounding operations. A MathContext
* encapsulates a RoundingMode and the number of significant digits in the output.
*
* @param mathContext The math context to use when rounding is required.
* @return The property bag, for chaining.
* @see MathContext
* @see #setRoundingMode
*/
public IBasicRoundingProperties setMathContext(MathContext mathContext);
}
public static interface MultiplierGenerator {
public int getMultiplier(int magnitude);
}
// Properties available to all rounding strategies
protected final MathContext mathContext;
protected final int minInt;
protected final int maxInt;
protected final int minFrac;
protected final int maxFrac;
/**
* Constructor that uses integer and fraction digit lengths from IBasicRoundingProperties.
*
* @param properties
*/
protected Rounder(IBasicRoundingProperties properties) {
mathContext = RoundingUtils.getMathContextOrUnlimited(properties);
int _maxInt = properties.getMaximumIntegerDigits();
int _minInt = properties.getMinimumIntegerDigits();
int _maxFrac = properties.getMaximumFractionDigits();
int _minFrac = properties.getMinimumFractionDigits();
// Validate min/max int/frac.
// For backwards compatibility, minimum overrides maximum if the two conflict.
// The following logic ensures that there is always a minimum of at least one digit.
if (_minInt == 0 && _maxFrac != 0) {
// Force a digit after the decimal point.
minFrac = _minFrac <= 0 ? 1 : _minFrac;
maxFrac = _maxFrac < 0 ? Integer.MAX_VALUE : _maxFrac < minFrac ? minFrac : _maxFrac;
minInt = 0;
maxInt = _maxInt < 0 ? Integer.MAX_VALUE : _maxInt;
} else {
// Force a digit before the decimal point.
minFrac = _minFrac < 0 ? 0 : _minFrac;
maxFrac = _maxFrac < 0 ? Integer.MAX_VALUE : _maxFrac < minFrac ? minFrac : _maxFrac;
minInt = _minInt <= 0 ? 1 : _minInt;
maxInt = _maxInt < 0 ? Integer.MAX_VALUE : _maxInt < minInt ? minInt : _maxInt;
}
}
/**
* Perform rounding and specification of integer and fraction digit lengths on the input quantity.
* Calling this method will change the state of the FormatQuantity.
*
* @param input The {@link FormatQuantity} to be modified and rounded.
*/
public abstract void apply(FormatQuantity input);
/**
* Rounding can affect the magnitude. First we attempt to adjust according to the original
* magnitude, and if the magnitude changes, we adjust according to a magnitude one greater. Note
* that this algorithm assumes that increasing the multiplier never increases the number of digits
* that can be displayed.
*
* @param input The quantity to be rounded.
* @param mg The implementation that returns magnitude adjustment based on a given starting
* magnitude.
* @return The multiplier that was chosen to best fit the input.
*/
public int chooseMultiplierAndApply(FormatQuantity input, MultiplierGenerator mg) {
// TODO: Avoid the object creation here.
FormatQuantity copy = input.createCopy();
int magnitude = input.getMagnitude();
int multiplier = mg.getMultiplier(magnitude);
input.adjustMagnitude(multiplier);
apply(input);
if (input.getMagnitude() == magnitude + multiplier + 1) {
magnitude += 1;
input.copyFrom(copy);
multiplier = mg.getMultiplier(magnitude);
input.adjustMagnitude(multiplier);
assert input.getMagnitude() == magnitude + multiplier - 1;
apply(input);
assert input.getMagnitude() == magnitude + multiplier;
}
return multiplier;
}
/**
* Implementations can call this method to perform default logic for min/max digits. This method
* performs logic for handling of a zero input.
*
* @param input The digits being formatted.
*/
protected void applyDefaults(FormatQuantity input) {
input.setIntegerFractionLength(minInt, maxInt, minFrac, maxFrac);
}
@Override
public void before(FormatQuantity input, ModifierHolder mods) {
apply(input);
}
@Override
public void export(Properties properties) {
properties.setMathContext(mathContext);
properties.setRoundingMode(mathContext.getRoundingMode());
properties.setMinimumFractionDigits(minFrac);
properties.setMinimumIntegerDigits(minInt);
properties.setMaximumFractionDigits(maxFrac);
properties.setMaximumIntegerDigits(maxInt);
}
}