| /* 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.BigDecimal; |
| import java.math.BigInteger; |
| import java.math.MathContext; |
| import java.text.FieldPosition; |
| |
| import android.icu.impl.StandardPlural; |
| import android.icu.text.PluralRules; |
| import android.icu.text.PluralRules.Operand; |
| import android.icu.text.UFieldPosition; |
| |
| /** |
| * Represents numbers and digit display properties using Binary Coded Decimal (BCD). |
| * |
| * @implements {@link FormatQuantity} |
| * @hide Only a subset of ICU is exposed in Android |
| */ |
| public abstract class FormatQuantityBCD implements FormatQuantity { |
| |
| /** |
| * The power of ten corresponding to the least significant digit in the BCD. For example, if this |
| * object represents the number "3.14", the BCD will be "0x314" and the scale will be -2. |
| * |
| * <p>Note that in {@link java.math.BigDecimal}, the scale is defined differently: the number of |
| * digits after the decimal place, which is the negative of our definition of scale. |
| */ |
| protected int scale; |
| |
| /** |
| * The number of digits in the BCD. For example, "1007" has BCD "0x1007" and precision 4. The |
| * maximum precision is 16 since a long can hold only 16 digits. |
| * |
| * <p>This value must be re-calculated whenever the value in bcd changes by using {@link |
| * #computePrecisionAndCompact()}. |
| */ |
| protected int precision; |
| |
| /** |
| * A bitmask of properties relating to the number represented by this object. |
| * |
| * @see #NEGATIVE_FLAG |
| * @see #INFINITY_FLAG |
| * @see #NAN_FLAG |
| */ |
| protected int flags; |
| |
| protected static final int NEGATIVE_FLAG = 1; |
| protected static final int INFINITY_FLAG = 2; |
| protected static final int NAN_FLAG = 4; |
| |
| // The following three fields relate to the double-to-ascii fast path algorithm. |
| // When a double is given to FormatQuantityBCD, it is converted to using a fast algorithm. The |
| // fast algorithm guarantees correctness to only the first ~12 digits of the double. The process |
| // of rounding the number ensures that the converted digits are correct, falling back to a slow- |
| // path algorithm if required. Therefore, if a FormatQuantity is constructed from a double, it |
| // is *required* that roundToMagnitude(), roundToIncrement(), or roundToInfinity() is called. If |
| // you don't round, assertions will fail in certain other methods if you try calling them. |
| |
| /** |
| * The original number provided by the user and which is represented in BCD. Used when we need to |
| * re-compute the BCD for an exact double representation. |
| */ |
| protected double origDouble; |
| |
| /** |
| * The change in magnitude relative to the original double. Used when we need to re-compute the |
| * BCD for an exact double representation. |
| */ |
| protected int origDelta; |
| |
| /** |
| * Whether the value in the BCD comes from the double fast path without having been rounded to |
| * ensure correctness |
| */ |
| protected boolean isApproximate; |
| |
| // Four positions: left optional '(', left required '[', right required ']', right optional ')'. |
| // These four positions determine which digits are displayed in the output string. They do NOT |
| // affect rounding. These positions are internal-only and can be specified only by the public |
| // endpoints like setFractionLength, setIntegerLength, and setSignificantDigits, among others. |
| // |
| // * Digits between lReqPos and rReqPos are in the "required zone" and are always displayed. |
| // * Digits between lOptPos and rOptPos but outside the required zone are in the "optional zone" |
| // and are displayed unless they are trailing off the left or right edge of the number and |
| // have a numerical value of zero. In order to be "trailing", the digits need to be beyond |
| // the decimal point in their respective directions. |
| // * Digits outside of the "optional zone" are never displayed. |
| // |
| // See the table below for illustrative examples. |
| // |
| // +---------+---------+---------+---------+------------+------------------------+--------------+ |
| // | lOptPos | lReqPos | rReqPos | rOptPos | number | positions | en-US string | |
| // +---------+---------+---------+---------+------------+------------------------+--------------+ |
| // | 5 | 2 | -1 | -5 | 1234.567 | ( 12[34.5]67 ) | 1,234.567 | |
| // | 3 | 2 | -1 | -5 | 1234.567 | 1(2[34.5]67 ) | 234.567 | |
| // | 3 | 2 | -1 | -2 | 1234.567 | 1(2[34.5]6)7 | 234.56 | |
| // | 6 | 4 | 2 | -5 | 123456789. | 123(45[67]89. ) | 456,789. | |
| // | 6 | 4 | 2 | 1 | 123456789. | 123(45[67]8)9. | 456,780. | |
| // | -1 | -1 | -3 | -4 | 0.123456 | 0.1([23]4)56 | .0234 | |
| // | 6 | 4 | -2 | -2 | 12.3 | ( [ 12.3 ]) | 0012.30 | |
| // +---------+---------+---------+---------+------------+------------------------+--------------+ |
| // |
| protected int lOptPos = Integer.MAX_VALUE; |
| protected int lReqPos = 0; |
| protected int rReqPos = 0; |
| protected int rOptPos = Integer.MIN_VALUE; |
| |
| @Override |
| public void copyFrom(FormatQuantity _other) { |
| copyBcdFrom(_other); |
| FormatQuantityBCD other = (FormatQuantityBCD) _other; |
| lOptPos = other.lOptPos; |
| lReqPos = other.lReqPos; |
| rReqPos = other.rReqPos; |
| rOptPos = other.rOptPos; |
| scale = other.scale; |
| precision = other.precision; |
| flags = other.flags; |
| origDouble = other.origDouble; |
| origDelta = other.origDelta; |
| isApproximate = other.isApproximate; |
| } |
| |
| public FormatQuantityBCD clear() { |
| lOptPos = Integer.MAX_VALUE; |
| lReqPos = 0; |
| rReqPos = 0; |
| rOptPos = Integer.MIN_VALUE; |
| flags = 0; |
| setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data |
| return this; |
| } |
| |
| @Override |
| public void setIntegerFractionLength(int minInt, int maxInt, int minFrac, int maxFrac) { |
| // Validation should happen outside of FormatQuantity, e.g., in the Rounder class. |
| assert minInt >= 0; |
| assert maxInt >= minInt; |
| assert minFrac >= 0; |
| assert maxFrac >= minFrac; |
| |
| // Save values into internal state |
| // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE |
| lOptPos = maxInt; |
| lReqPos = minInt; |
| rReqPos = -minFrac; |
| rOptPos = -maxFrac; |
| } |
| |
| @Override |
| public long getPositionFingerprint() { |
| long fingerprint = 0; |
| fingerprint ^= lOptPos; |
| fingerprint ^= (lReqPos << 16); |
| fingerprint ^= ((long) rReqPos << 32); |
| fingerprint ^= ((long) rOptPos << 48); |
| return fingerprint; |
| } |
| |
| @Override |
| public void roundToIncrement(BigDecimal roundingInterval, MathContext mathContext) { |
| // TODO: Avoid converting back and forth to BigDecimal. |
| BigDecimal temp = toBigDecimal(); |
| temp = |
| temp.divide(roundingInterval, 0, mathContext.getRoundingMode()) |
| .multiply(roundingInterval) |
| .round(mathContext); |
| if (temp.signum() == 0) { |
| setBcdToZero(); // keeps negative flag for -0.0 |
| } else { |
| setToBigDecimal(temp); |
| } |
| } |
| |
| @Override |
| public void multiplyBy(BigDecimal multiplicand) { |
| BigDecimal temp = toBigDecimal(); |
| temp = temp.multiply(multiplicand); |
| setToBigDecimal(temp); |
| } |
| |
| @Override |
| public int getMagnitude() throws ArithmeticException { |
| if (precision == 0) { |
| throw new ArithmeticException("Magnitude is not well-defined for zero"); |
| } else { |
| return scale + precision - 1; |
| } |
| } |
| |
| @Override |
| public void adjustMagnitude(int delta) { |
| if (precision != 0) { |
| scale += delta; |
| origDelta += delta; |
| } |
| } |
| |
| @Override |
| public StandardPlural getStandardPlural(PluralRules rules) { |
| if (rules == null) { |
| // Fail gracefully if the user didn't provide a PluralRules |
| return StandardPlural.OTHER; |
| } else { |
| @SuppressWarnings("deprecation") |
| String ruleString = rules.select(this); |
| return StandardPlural.orOtherFromString(ruleString); |
| } |
| } |
| |
| @Override |
| public double getPluralOperand(Operand operand) { |
| // If this assertion fails, you need to call roundToInfinity() or some other rounding method. |
| // See the comment at the top of this file explaining the "isApproximate" field. |
| assert !isApproximate; |
| |
| switch (operand) { |
| case i: |
| return toLong(); |
| case f: |
| return toFractionLong(true); |
| case t: |
| return toFractionLong(false); |
| case v: |
| return fractionCount(); |
| case w: |
| return fractionCountWithoutTrailingZeros(); |
| default: |
| return Math.abs(toDouble()); |
| } |
| } |
| |
| /** |
| * If the given {@link FieldPosition} is a {@link UFieldPosition}, populates it with the fraction |
| * length and fraction long value. If the argument is not a {@link UFieldPosition}, nothing |
| * happens. |
| * |
| * @param fp The {@link UFieldPosition} to populate. |
| */ |
| public void populateUFieldPosition(FieldPosition fp) { |
| if (fp instanceof UFieldPosition) { |
| ((UFieldPosition) fp) |
| .setFractionDigits((int) getPluralOperand(Operand.v), (long) getPluralOperand(Operand.f)); |
| } |
| } |
| |
| @Override |
| public int getUpperDisplayMagnitude() { |
| // If this assertion fails, you need to call roundToInfinity() or some other rounding method. |
| // See the comment at the top of this file explaining the "isApproximate" field. |
| assert !isApproximate; |
| |
| int magnitude = scale + precision; |
| int result = (lReqPos > magnitude) ? lReqPos : (lOptPos < magnitude) ? lOptPos : magnitude; |
| return result - 1; |
| } |
| |
| @Override |
| public int getLowerDisplayMagnitude() { |
| // If this assertion fails, you need to call roundToInfinity() or some other rounding method. |
| // See the comment at the top of this file explaining the "isApproximate" field. |
| assert !isApproximate; |
| |
| int magnitude = scale; |
| int result = (rReqPos < magnitude) ? rReqPos : (rOptPos > magnitude) ? rOptPos : magnitude; |
| return result; |
| } |
| |
| @Override |
| public byte getDigit(int magnitude) { |
| // If this assertion fails, you need to call roundToInfinity() or some other rounding method. |
| // See the comment at the top of this file explaining the "isApproximate" field. |
| assert !isApproximate; |
| |
| return getDigitPos(magnitude - scale); |
| } |
| |
| private int fractionCount() { |
| return -getLowerDisplayMagnitude(); |
| } |
| |
| private int fractionCountWithoutTrailingZeros() { |
| return Math.max(-scale, 0); |
| } |
| |
| @Override |
| public boolean isNegative() { |
| return (flags & NEGATIVE_FLAG) != 0; |
| } |
| |
| @Override |
| public boolean isInfinite() { |
| return (flags & INFINITY_FLAG) != 0; |
| } |
| |
| @Override |
| public boolean isNaN() { |
| return (flags & NAN_FLAG) != 0; |
| } |
| |
| @Override |
| public boolean isZero() { |
| return precision == 0; |
| } |
| |
| @Override |
| public FormatQuantity createCopy() { |
| if (this instanceof FormatQuantity2) { |
| return new FormatQuantity2((FormatQuantity2) this); |
| } else if (this instanceof FormatQuantity3) { |
| return new FormatQuantity3((FormatQuantity3) this); |
| } else if (this instanceof FormatQuantity4) { |
| return new FormatQuantity4((FormatQuantity4) this); |
| } else { |
| throw new IllegalArgumentException("Don't know how to copy " + this.getClass()); |
| } |
| } |
| |
| public void setToInt(int n) { |
| setBcdToZero(); |
| flags = 0; |
| if (n < 0) { |
| flags |= NEGATIVE_FLAG; |
| n = -n; |
| } |
| if (n != 0) { |
| _setToInt(n); |
| compact(); |
| } |
| } |
| |
| private void _setToInt(int n) { |
| if (n == Integer.MIN_VALUE) { |
| readLongToBcd(-(long) n); |
| } else { |
| readIntToBcd(n); |
| } |
| } |
| |
| public void setToLong(long n) { |
| setBcdToZero(); |
| flags = 0; |
| if (n < 0) { |
| flags |= NEGATIVE_FLAG; |
| n = -n; |
| } |
| if (n != 0) { |
| _setToLong(n); |
| compact(); |
| } |
| } |
| |
| private void _setToLong(long n) { |
| if (n == Long.MIN_VALUE) { |
| readBigIntegerToBcd(BigInteger.valueOf(n).negate()); |
| } else if (n <= Integer.MAX_VALUE) { |
| readIntToBcd((int) n); |
| } else { |
| readLongToBcd(n); |
| } |
| } |
| |
| public void setToBigInteger(BigInteger n) { |
| setBcdToZero(); |
| flags = 0; |
| if (n.signum() == -1) { |
| flags |= NEGATIVE_FLAG; |
| n = n.negate(); |
| } |
| if (n.signum() != 0) { |
| _setToBigInteger(n); |
| compact(); |
| } |
| } |
| |
| private void _setToBigInteger(BigInteger n) { |
| if (n.bitLength() < 32) { |
| readIntToBcd(n.intValue()); |
| } else if (n.bitLength() < 64) { |
| readLongToBcd(n.longValue()); |
| } else { |
| readBigIntegerToBcd(n); |
| } |
| } |
| |
| /** |
| * Sets the internal BCD state to represent the value in the given double. |
| * |
| * @param n The value to consume. |
| */ |
| public void setToDouble(double n) { |
| setBcdToZero(); |
| flags = 0; |
| // Double.compare() handles +0.0 vs -0.0 |
| if (Double.compare(n, 0.0) < 0) { |
| flags |= NEGATIVE_FLAG; |
| n = -n; |
| } |
| if (Double.isNaN(n)) { |
| flags |= NAN_FLAG; |
| } else if (Double.isInfinite(n)) { |
| flags |= INFINITY_FLAG; |
| } else if (n != 0) { |
| _setToDoubleFast(n); |
| compact(); |
| } |
| } |
| |
| private static final double[] DOUBLE_MULTIPLIERS = { |
| 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, |
| 1e17, 1e18, 1e19, 1e20, 1e21 |
| }; |
| |
| /** |
| * Uses double multiplication and division to get the number into integer space before converting |
| * to digits. Since double arithmetic is inexact, the resulting digits may not be accurate. |
| */ |
| private void _setToDoubleFast(double n) { |
| long ieeeBits = Double.doubleToLongBits(n); |
| int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff; |
| |
| // Not all integers can be represented exactly for exponent > 52 |
| if (exponent <= 52 && (long) n == n) { |
| _setToLong((long) n); |
| return; |
| } |
| |
| isApproximate = true; |
| origDouble = n; |
| origDelta = 0; |
| |
| // 3.3219... is log2(10) |
| int fracLength = (int) ((52 - exponent) / 3.32192809489); |
| if (fracLength >= 0) { |
| int i = fracLength; |
| // 1e22 is the largest exact double. |
| for (; i >= 22; i -= 22) n *= 1e22; |
| n *= DOUBLE_MULTIPLIERS[i]; |
| } else { |
| int i = fracLength; |
| // 1e22 is the largest exact double. |
| for (; i <= -22; i += 22) n /= 1e22; |
| n /= DOUBLE_MULTIPLIERS[-i]; |
| } |
| long result = Math.round(n); |
| if (result != 0) { |
| _setToLong(result); |
| scale -= fracLength; |
| } |
| } |
| |
| /** |
| * Uses Double.toString() to obtain an exact accurate representation of the double, overwriting it |
| * into the BCD. This method can be called at any point after {@link #_setToDoubleFast} while |
| * {@link #isApproximate} is still true. |
| */ |
| private void convertToAccurateDouble() { |
| double n = origDouble; |
| assert n != 0; |
| int delta = origDelta; |
| setBcdToZero(); |
| |
| // Call the slow oracle function |
| String temp = Double.toString(n); |
| |
| if (temp.indexOf('E') != -1) { |
| // Case 1: Exponential notation. |
| assert temp.indexOf('.') == 1; |
| int expPos = temp.indexOf('E'); |
| _setToLong(Long.parseLong(temp.charAt(0) + temp.substring(2, expPos))); |
| scale += Integer.parseInt(temp.substring(expPos + 1)) - (expPos - 1) + 1; |
| } else if (temp.charAt(0) == '0') { |
| // Case 2: Fraction-only number. |
| assert temp.indexOf('.') == 1; |
| _setToLong(Long.parseLong(temp.substring(2))); |
| scale += 2 - temp.length(); |
| } else if (temp.charAt(temp.length() - 1) == '0') { |
| // Case 3: Integer-only number. |
| // Note: this path should not normally happen, because integer-only numbers are captured |
| // before the approximate double logic is performed. |
| assert temp.indexOf('.') == temp.length() - 2; |
| assert temp.length() - 2 <= 18; |
| _setToLong(Long.parseLong(temp.substring(0, temp.length() - 2))); |
| // no need to adjust scale |
| } else { |
| // Case 4: Number with both a fraction and an integer. |
| int decimalPos = temp.indexOf('.'); |
| _setToLong(Long.parseLong(temp.substring(0, decimalPos) + temp.substring(decimalPos + 1))); |
| scale += decimalPos - temp.length() + 1; |
| } |
| scale += delta; |
| compact(); |
| explicitExactDouble = true; |
| } |
| |
| /** |
| * Whether this {@link FormatQuantity4} has been explicitly converted to an exact double. true if |
| * backed by a double that was explicitly converted via convertToAccurateDouble; false otherwise. |
| * Used for testing. |
| * |
| * @deprecated This API is ICU internal only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated public boolean explicitExactDouble = false; |
| |
| /** |
| * Sets the internal BCD state to represent the value in the given BigDecimal. |
| * |
| * @param n The value to consume. |
| */ |
| public void setToBigDecimal(BigDecimal n) { |
| setBcdToZero(); |
| flags = 0; |
| if (n.signum() == -1) { |
| flags |= NEGATIVE_FLAG; |
| n = n.negate(); |
| } |
| if (n.signum() != 0) { |
| _setToBigDecimal(n); |
| compact(); |
| } |
| } |
| |
| private void _setToBigDecimal(BigDecimal n) { |
| int fracLength = n.scale(); |
| n = n.scaleByPowerOfTen(fracLength); |
| BigInteger bi = n.toBigInteger(); |
| _setToBigInteger(bi); |
| scale -= fracLength; |
| } |
| |
| /** |
| * Returns a long approximating the internal BCD. A long can only represent the integral part of |
| * the number. |
| * |
| * @return A double representation of the internal BCD. |
| */ |
| protected long toLong() { |
| long result = 0L; |
| for (int magnitude = scale + precision - 1; magnitude >= 0; magnitude--) { |
| result = result * 10 + getDigitPos(magnitude - scale); |
| } |
| return result; |
| } |
| |
| /** |
| * This returns a long representing the fraction digits of the number, as required by PluralRules. |
| * For example, if we represent the number "1.20" (including optional and required digits), then |
| * this function returns "20" if includeTrailingZeros is true or "2" if false. |
| */ |
| protected long toFractionLong(boolean includeTrailingZeros) { |
| long result = 0L; |
| int magnitude = -1; |
| for (; |
| (magnitude >= scale || (includeTrailingZeros && magnitude >= rReqPos)) |
| && magnitude >= rOptPos; |
| magnitude--) { |
| result = result * 10 + getDigitPos(magnitude - scale); |
| } |
| return result; |
| } |
| |
| /** |
| * Returns a double approximating the internal BCD. The double may not retain all of the |
| * information encoded in the BCD if the BCD represents a number out of range of a double. |
| * |
| * @return A double representation of the internal BCD. |
| */ |
| @Override |
| public double toDouble() { |
| if (isApproximate) { |
| return toDoubleFromOriginal(); |
| } |
| |
| if (isNaN()) { |
| return Double.NaN; |
| } else if (isInfinite()) { |
| return isNegative() ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; |
| } |
| |
| long tempLong = 0L; |
| int lostDigits = precision - Math.min(precision, 17); |
| for (int shift = precision - 1; shift >= lostDigits; shift--) { |
| tempLong = tempLong * 10 + getDigitPos(shift); |
| } |
| double result = tempLong; |
| int _scale = scale + lostDigits; |
| if (_scale >= 0) { |
| // 1e22 is the largest exact double. |
| int i = _scale; |
| for (; i >= 22; i -= 22) result *= 1e22; |
| result *= DOUBLE_MULTIPLIERS[i]; |
| } else { |
| // 1e22 is the largest exact double. |
| int i = _scale; |
| for (; i <= -22; i += 22) result /= 1e22; |
| result /= DOUBLE_MULTIPLIERS[-i]; |
| } |
| if (isNegative()) result = -result; |
| return result; |
| } |
| |
| @Override |
| public BigDecimal toBigDecimal() { |
| if (isApproximate) { |
| // Converting to a BigDecimal requires Double.toString(). |
| convertToAccurateDouble(); |
| } |
| return bcdToBigDecimal(); |
| } |
| |
| protected double toDoubleFromOriginal() { |
| double result = origDouble; |
| int delta = origDelta; |
| if (delta >= 0) { |
| // 1e22 is the largest exact double. |
| for (; delta >= 22; delta -= 22) result *= 1e22; |
| result *= DOUBLE_MULTIPLIERS[delta]; |
| } else { |
| // 1e22 is the largest exact double. |
| for (; delta <= -22; delta += 22) result /= 1e22; |
| result /= DOUBLE_MULTIPLIERS[-delta]; |
| } |
| if (isNegative()) result *= -1; |
| return result; |
| } |
| |
| private static int safeSubtract(int a, int b) { |
| int diff = a - b; |
| if (b < 0 && diff < a) return Integer.MAX_VALUE; |
| if (b > 0 && diff > a) return Integer.MIN_VALUE; |
| return diff; |
| } |
| |
| @Override |
| public void roundToMagnitude(int magnitude, MathContext mathContext) { |
| // The position in the BCD at which rounding will be performed; digits to the right of position |
| // will be rounded away. |
| // TODO: Andy: There was a test failure because of integer overflow here. Should I do |
| // "safe subtraction" everywhere in the code? What's the nicest way to do it? |
| int position = safeSubtract(magnitude, scale); |
| |
| // Enforce the number of digits required by the MathContext. |
| int _mcPrecision = mathContext.getPrecision(); |
| if (magnitude == Integer.MAX_VALUE |
| || (_mcPrecision > 0 && precision - position > _mcPrecision)) { |
| position = precision - _mcPrecision; |
| } |
| |
| if (position <= 0 && !isApproximate) { |
| // All digits are to the left of the rounding magnitude. |
| } else if (precision == 0) { |
| // No rounding for zero. |
| } else { |
| // Perform rounding logic. |
| // "leading" = most significant digit to the right of rounding |
| // "trailing" = least significant digit to the left of rounding |
| byte leadingDigit = getDigitPos(safeSubtract(position, 1)); |
| byte trailingDigit = getDigitPos(position); |
| |
| // Compute which section of the number we are in. |
| // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles) |
| // LOWER means we are between the bottom edge and the midpoint, like 1.391 |
| // MIDPOINT means we are exactly in the middle, like 1.500 |
| // UPPER means we are between the midpoint and the top edge, like 1.916 |
| int section = RoundingUtils.SECTION_MIDPOINT; |
| if (!isApproximate) { |
| if (leadingDigit < 5) { |
| section = RoundingUtils.SECTION_LOWER; |
| } else if (leadingDigit > 5) { |
| section = RoundingUtils.SECTION_UPPER; |
| } else { |
| for (int p = safeSubtract(position, 2); p >= 0; p--) { |
| if (getDigitPos(p) != 0) { |
| section = RoundingUtils.SECTION_UPPER; |
| break; |
| } |
| } |
| } |
| } else { |
| int p = safeSubtract(position, 2); |
| int minP = Math.max(0, precision - 14); |
| if (leadingDigit == 0) { |
| section = -1; |
| for (; p >= minP; p--) { |
| if (getDigitPos(p) != 0) { |
| section = RoundingUtils.SECTION_LOWER; |
| break; |
| } |
| } |
| } else if (leadingDigit == 4) { |
| for (; p >= minP; p--) { |
| if (getDigitPos(p) != 9) { |
| section = RoundingUtils.SECTION_LOWER; |
| break; |
| } |
| } |
| } else if (leadingDigit == 5) { |
| for (; p >= minP; p--) { |
| if (getDigitPos(p) != 0) { |
| section = RoundingUtils.SECTION_UPPER; |
| break; |
| } |
| } |
| } else if (leadingDigit == 9) { |
| section = -2; |
| for (; p >= minP; p--) { |
| if (getDigitPos(p) != 9) { |
| section = RoundingUtils.SECTION_UPPER; |
| break; |
| } |
| } |
| } else if (leadingDigit < 5) { |
| section = RoundingUtils.SECTION_LOWER; |
| } else { |
| section = RoundingUtils.SECTION_UPPER; |
| } |
| |
| boolean roundsAtMidpoint = |
| RoundingUtils.roundsAtMidpoint(mathContext.getRoundingMode().ordinal()); |
| if (safeSubtract(position, 1) < precision - 14 |
| || (roundsAtMidpoint && section == RoundingUtils.SECTION_MIDPOINT) |
| || (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) { |
| // Oops! This means that we have to get the exact representation of the double, because |
| // the zone of uncertainty is along the rounding boundary. |
| convertToAccurateDouble(); |
| roundToMagnitude(magnitude, mathContext); // start over |
| return; |
| } |
| |
| // Turn off the approximate double flag, since the value is now confirmed to be exact. |
| isApproximate = false; |
| origDouble = 0.0; |
| origDelta = 0; |
| |
| if (position <= 0) { |
| // All digits are to the left of the rounding magnitude. |
| return; |
| } |
| |
| // Good to continue rounding. |
| if (section == -1) section = RoundingUtils.SECTION_LOWER; |
| if (section == -2) section = RoundingUtils.SECTION_UPPER; |
| } |
| |
| boolean roundDown = |
| RoundingUtils.getRoundingDirection( |
| (trailingDigit % 2) == 0, |
| isNegative(), |
| section, |
| mathContext.getRoundingMode().ordinal(), |
| this); |
| |
| // Perform truncation |
| if (position >= precision) { |
| setBcdToZero(); |
| scale = magnitude; |
| } else { |
| shiftRight(position); |
| } |
| |
| // Bubble the result to the higher digits |
| if (!roundDown) { |
| if (trailingDigit == 9) { |
| int bubblePos = 0; |
| // Note: in the long implementation, the most digits BCD can have at this point is 15, |
| // so bubblePos <= 15 and getDigitPos(bubblePos) is safe. |
| for (; getDigitPos(bubblePos) == 9; bubblePos++) {} |
| shiftRight(bubblePos); // shift off the trailing 9s |
| } |
| byte digit0 = getDigitPos(0); |
| assert digit0 != 9; |
| setDigitPos(0, (byte) (digit0 + 1)); |
| precision += 1; // in case an extra digit got added |
| } |
| |
| compact(); |
| } |
| } |
| |
| @Override |
| public void roundToInfinity() { |
| if (isApproximate) { |
| convertToAccurateDouble(); |
| } |
| } |
| |
| /** |
| * Appends a digit, optionally with one or more leading zeros, to the end of the value represented |
| * by this FormatQuantity. |
| * |
| * <p>The primary use of this method is to construct numbers during a parsing loop. It allows |
| * parsing to take advantage of the digit list infrastructure primarily designed for formatting. |
| * |
| * @param value The digit to append. |
| * @param leadingZeros The number of zeros to append before the digit. For example, if the value |
| * in this instance starts as 12.3, and you append a 4 with 1 leading zero, the value becomes |
| * 12.304. |
| * @param appendAsInteger If true, increase the magnitude of existing digits to make room for the |
| * new digit. If false, append to the end like a fraction digit. If true, there must not be |
| * any fraction digits already in the number. |
| * @deprecated This API is ICU internal only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public void appendDigit(byte value, int leadingZeros, boolean appendAsInteger) { |
| assert leadingZeros >= 0; |
| |
| // Zero requires special handling to maintain the invariant that the least-significant digit |
| // in the BCD is nonzero. |
| if (value == 0) { |
| if (appendAsInteger && precision != 0) { |
| scale += leadingZeros + 1; |
| } |
| return; |
| } |
| |
| // Deal with trailing zeros |
| if (scale > 0) { |
| leadingZeros += scale; |
| if (appendAsInteger) { |
| scale = 0; |
| } |
| } |
| |
| // Append digit |
| shiftLeft(leadingZeros + 1); |
| setDigitPos(0, value); |
| |
| // Fix scale if in integer mode |
| if (appendAsInteger) { |
| scale += leadingZeros + 1; |
| } |
| } |
| |
| /** |
| * Returns a single digit from the BCD list. No internal state is changed by calling this method. |
| * |
| * @param position The position of the digit to pop, counted in BCD units from the least |
| * significant digit. If outside the range supported by the implementation, zero is returned. |
| * @return The digit at the specified location. |
| */ |
| protected abstract byte getDigitPos(int position); |
| |
| /** |
| * Sets the digit in the BCD list. This method only sets the digit; it is the caller's |
| * responsibility to call {@link #compact} after setting the digit. |
| * |
| * @param position The position of the digit to pop, counted in BCD units from the least |
| * significant digit. If outside the range supported by the implementation, an AssertionError |
| * is thrown. |
| * @param value The digit to set at the specified location. |
| */ |
| protected abstract void setDigitPos(int position, byte value); |
| |
| /** |
| * Adds zeros to the end of the BCD list. This will result in an invalid BCD representation; it is |
| * the caller's responsibility to do further manipulation and then call {@link #compact}. |
| * |
| * @param numDigits The number of zeros to add. |
| */ |
| protected abstract void shiftLeft(int numDigits); |
| |
| protected abstract void shiftRight(int numDigits); |
| |
| /** |
| * Sets the internal representation to zero. Clears any values stored in scale, precision, |
| * hasDouble, origDouble, origDelta, and BCD data. |
| */ |
| protected abstract void setBcdToZero(); |
| |
| /** |
| * Sets the internal BCD state to represent the value in the given int. The int is guaranteed to |
| * be either positive. The internal state is guaranteed to be empty when this method is called. |
| * |
| * @param n The value to consume. |
| */ |
| protected abstract void readIntToBcd(int input); |
| |
| /** |
| * Sets the internal BCD state to represent the value in the given long. The long is guaranteed to |
| * be either positive. The internal state is guaranteed to be empty when this method is called. |
| * |
| * @param n The value to consume. |
| */ |
| protected abstract void readLongToBcd(long input); |
| |
| /** |
| * Sets the internal BCD state to represent the value in the given BigInteger. The BigInteger is |
| * guaranteed to be positive, and it is guaranteed to be larger than Long.MAX_VALUE. The internal |
| * state is guaranteed to be empty when this method is called. |
| * |
| * @param n The value to consume. |
| */ |
| protected abstract void readBigIntegerToBcd(BigInteger input); |
| |
| /** |
| * Returns a BigDecimal encoding the internal BCD value. |
| * |
| * @return A BigDecimal representation of the internal BCD. |
| */ |
| protected abstract BigDecimal bcdToBigDecimal(); |
| |
| protected abstract void copyBcdFrom(FormatQuantity _other); |
| |
| /** |
| * Removes trailing zeros from the BCD (adjusting the scale as required) and then computes the |
| * precision. The precision is the number of digits in the number up through the greatest nonzero |
| * digit. |
| * |
| * <p>This method must always be called when bcd changes in order for assumptions to be correct in |
| * methods like {@link #fractionCount()}. |
| */ |
| protected abstract void compact(); |
| } |