Home | History | Annotate | Download | only in number
      1 /* GENERATED SOURCE. DO NOT MODIFY. */
      2 //  2017 and later: Unicode, Inc. and others.
      3 // License & terms of use: http://www.unicode.org/copyright.html#License
      4 package android.icu.impl.number;
      5 
      6 import java.math.BigDecimal;
      7 import java.math.BigInteger;
      8 import java.math.MathContext;
      9 import java.text.FieldPosition;
     10 
     11 import android.icu.impl.StandardPlural;
     12 import android.icu.text.PluralRules;
     13 import android.icu.text.PluralRules.Operand;
     14 import android.icu.text.UFieldPosition;
     15 
     16 /**
     17  * Represents numbers and digit display properties using Binary Coded Decimal (BCD).
     18  *
     19  * @implements {@link DecimalQuantity}
     20  * @hide Only a subset of ICU is exposed in Android
     21  */
     22 public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
     23 
     24   /**
     25    * The power of ten corresponding to the least significant digit in the BCD. For example, if this
     26    * object represents the number "3.14", the BCD will be "0x314" and the scale will be -2.
     27    *
     28    * <p>Note that in {@link java.math.BigDecimal}, the scale is defined differently: the number of
     29    * digits after the decimal place, which is the negative of our definition of scale.
     30    */
     31   protected int scale;
     32 
     33   /**
     34    * The number of digits in the BCD. For example, "1007" has BCD "0x1007" and precision 4. The
     35    * maximum precision is 16 since a long can hold only 16 digits.
     36    *
     37    * <p>This value must be re-calculated whenever the value in bcd changes by using {@link
     38    * #computePrecisionAndCompact()}.
     39    */
     40   protected int precision;
     41 
     42   /**
     43    * A bitmask of properties relating to the number represented by this object.
     44    *
     45    * @see #NEGATIVE_FLAG
     46    * @see #INFINITY_FLAG
     47    * @see #NAN_FLAG
     48    */
     49   protected byte flags;
     50 
     51   protected static final int NEGATIVE_FLAG = 1;
     52   protected static final int INFINITY_FLAG = 2;
     53   protected static final int NAN_FLAG = 4;
     54 
     55   // The following three fields relate to the double-to-ascii fast path algorithm.
     56   // When a double is given to DecimalQuantityBCD, it is converted to using a fast algorithm. The
     57   // fast algorithm guarantees correctness to only the first ~12 digits of the double. The process
     58   // of rounding the number ensures that the converted digits are correct, falling back to a slow-
     59   // path algorithm if required.  Therefore, if a DecimalQuantity is constructed from a double, it
     60   // is *required* that roundToMagnitude(), roundToIncrement(), or roundToInfinity() is called. If
     61   // you don't round, assertions will fail in certain other methods if you try calling them.
     62 
     63   /**
     64    * The original number provided by the user and which is represented in BCD. Used when we need to
     65    * re-compute the BCD for an exact double representation.
     66    */
     67   protected double origDouble;
     68 
     69   /**
     70    * The change in magnitude relative to the original double. Used when we need to re-compute the
     71    * BCD for an exact double representation.
     72    */
     73   protected int origDelta;
     74 
     75   /**
     76    * Whether the value in the BCD comes from the double fast path without having been rounded to
     77    * ensure correctness
     78    */
     79   protected boolean isApproximate;
     80 
     81   // Four positions: left optional '(', left required '[', right required ']', right optional ')'.
     82   // These four positions determine which digits are displayed in the output string.  They do NOT
     83   // affect rounding.  These positions are internal-only and can be specified only by the public
     84   // endpoints like setFractionLength, setIntegerLength, and setSignificantDigits, among others.
     85   //
     86   //   * Digits between lReqPos and rReqPos are in the "required zone" and are always displayed.
     87   //   * Digits between lOptPos and rOptPos but outside the required zone are in the "optional zone"
     88   //     and are displayed unless they are trailing off the left or right edge of the number and
     89   //     have a numerical value of zero.  In order to be "trailing", the digits need to be beyond
     90   //     the decimal point in their respective directions.
     91   //   * Digits outside of the "optional zone" are never displayed.
     92   //
     93   // See the table below for illustrative examples.
     94   //
     95   // +---------+---------+---------+---------+------------+------------------------+--------------+
     96   // | lOptPos | lReqPos | rReqPos | rOptPos |   number   |        positions       | en-US string |
     97   // +---------+---------+---------+---------+------------+------------------------+--------------+
     98   // |    5    |    2    |   -1    |   -5    |   1234.567 |     ( 12[34.5]67  )    |   1,234.567  |
     99   // |    3    |    2    |   -1    |   -5    |   1234.567 |      1(2[34.5]67  )    |     234.567  |
    100   // |    3    |    2    |   -1    |   -2    |   1234.567 |      1(2[34.5]6)7      |     234.56   |
    101   // |    6    |    4    |    2    |   -5    | 123456789. |  123(45[67]89.     )   | 456,789.     |
    102   // |    6    |    4    |    2    |    1    | 123456789. |     123(45[67]8)9.     | 456,780.     |
    103   // |   -1    |   -1    |   -3    |   -4    | 0.123456   |     0.1([23]4)56       |        .0234 |
    104   // |    6    |    4    |   -2    |   -2    |     12.3   |     (  [  12.3 ])      |    0012.30   |
    105   // +---------+---------+---------+---------+------------+------------------------+--------------+
    106   //
    107   protected int lOptPos = Integer.MAX_VALUE;
    108   protected int lReqPos = 0;
    109   protected int rReqPos = 0;
    110   protected int rOptPos = Integer.MIN_VALUE;
    111 
    112   @Override
    113   public void copyFrom(DecimalQuantity _other) {
    114     copyBcdFrom(_other);
    115     DecimalQuantity_AbstractBCD other = (DecimalQuantity_AbstractBCD) _other;
    116     lOptPos = other.lOptPos;
    117     lReqPos = other.lReqPos;
    118     rReqPos = other.rReqPos;
    119     rOptPos = other.rOptPos;
    120     scale = other.scale;
    121     precision = other.precision;
    122     flags = other.flags;
    123     origDouble = other.origDouble;
    124     origDelta = other.origDelta;
    125     isApproximate = other.isApproximate;
    126   }
    127 
    128   public DecimalQuantity_AbstractBCD clear() {
    129     lOptPos = Integer.MAX_VALUE;
    130     lReqPos = 0;
    131     rReqPos = 0;
    132     rOptPos = Integer.MIN_VALUE;
    133     flags = 0;
    134     setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data
    135     return this;
    136   }
    137 
    138   @Override
    139   public void setIntegerLength(int minInt, int maxInt) {
    140     // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
    141     assert minInt >= 0;
    142     assert maxInt >= minInt;
    143 
    144     // Save values into internal state
    145     // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
    146     lOptPos = maxInt;
    147     lReqPos = minInt;
    148   }
    149 
    150   @Override
    151   public void setFractionLength(int minFrac, int maxFrac) {
    152     // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
    153     assert minFrac >= 0;
    154     assert maxFrac >= minFrac;
    155 
    156     // Save values into internal state
    157     // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
    158     rReqPos = -minFrac;
    159     rOptPos = -maxFrac;
    160   }
    161 
    162   @Override
    163   public long getPositionFingerprint() {
    164     long fingerprint = 0;
    165     fingerprint ^= lOptPos;
    166     fingerprint ^= (lReqPos << 16);
    167     fingerprint ^= ((long) rReqPos << 32);
    168     fingerprint ^= ((long) rOptPos << 48);
    169     return fingerprint;
    170   }
    171 
    172   @Override
    173   public void roundToIncrement(BigDecimal roundingIncrement, MathContext mathContext) {
    174     // TODO: Avoid converting back and forth to BigDecimal.
    175     BigDecimal temp = toBigDecimal();
    176     temp =
    177         temp.divide(roundingIncrement, 0, mathContext.getRoundingMode())
    178             .multiply(roundingIncrement)
    179             .round(mathContext);
    180     if (temp.signum() == 0) {
    181       setBcdToZero(); // keeps negative flag for -0.0
    182     } else {
    183       setToBigDecimal(temp);
    184     }
    185   }
    186 
    187   @Override
    188   public void multiplyBy(BigDecimal multiplicand) {
    189     if (isInfinite() || isZero() || isNaN()) {
    190       return;
    191     }
    192     BigDecimal temp = toBigDecimal();
    193     temp = temp.multiply(multiplicand);
    194     setToBigDecimal(temp);
    195   }
    196 
    197   @Override
    198   public int getMagnitude() throws ArithmeticException {
    199     if (precision == 0) {
    200       throw new ArithmeticException("Magnitude is not well-defined for zero");
    201     } else {
    202       return scale + precision - 1;
    203     }
    204   }
    205 
    206   @Override
    207   public void adjustMagnitude(int delta) {
    208     if (precision != 0) {
    209       scale += delta;
    210       origDelta += delta;
    211     }
    212   }
    213 
    214   @Override
    215   public StandardPlural getStandardPlural(PluralRules rules) {
    216     if (rules == null) {
    217       // Fail gracefully if the user didn't provide a PluralRules
    218       return StandardPlural.OTHER;
    219     } else {
    220       @SuppressWarnings("deprecation")
    221       String ruleString = rules.select(this);
    222       return StandardPlural.orOtherFromString(ruleString);
    223     }
    224   }
    225 
    226   @Override
    227   public double getPluralOperand(Operand operand) {
    228     // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
    229     // See the comment at the top of this file explaining the "isApproximate" field.
    230     assert !isApproximate;
    231 
    232     switch (operand) {
    233       case i:
    234         return toLong();
    235       case f:
    236         return toFractionLong(true);
    237       case t:
    238         return toFractionLong(false);
    239       case v:
    240         return fractionCount();
    241       case w:
    242         return fractionCountWithoutTrailingZeros();
    243       default:
    244         return Math.abs(toDouble());
    245     }
    246   }
    247 
    248   @Override
    249   public void populateUFieldPosition(FieldPosition fp) {
    250     if (fp instanceof UFieldPosition) {
    251       ((UFieldPosition) fp)
    252           .setFractionDigits((int) getPluralOperand(Operand.v), (long) getPluralOperand(Operand.f));
    253     }
    254   }
    255 
    256   @Override
    257   public int getUpperDisplayMagnitude() {
    258     // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
    259     // See the comment at the top of this file explaining the "isApproximate" field.
    260     assert !isApproximate;
    261 
    262     int magnitude = scale + precision;
    263     int result = (lReqPos > magnitude) ? lReqPos : (lOptPos < magnitude) ? lOptPos : magnitude;
    264     return result - 1;
    265   }
    266 
    267   @Override
    268   public int getLowerDisplayMagnitude() {
    269     // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
    270     // See the comment at the top of this file explaining the "isApproximate" field.
    271     assert !isApproximate;
    272 
    273     int magnitude = scale;
    274     int result = (rReqPos < magnitude) ? rReqPos : (rOptPos > magnitude) ? rOptPos : magnitude;
    275     return result;
    276   }
    277 
    278   @Override
    279   public byte getDigit(int magnitude) {
    280     // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
    281     // See the comment at the top of this file explaining the "isApproximate" field.
    282     assert !isApproximate;
    283 
    284     return getDigitPos(magnitude - scale);
    285   }
    286 
    287   private int fractionCount() {
    288     return -getLowerDisplayMagnitude();
    289   }
    290 
    291   private int fractionCountWithoutTrailingZeros() {
    292     return Math.max(-scale, 0);
    293   }
    294 
    295   @Override
    296   public boolean isNegative() {
    297     return (flags & NEGATIVE_FLAG) != 0;
    298   }
    299 
    300   @Override
    301   public boolean isInfinite() {
    302     return (flags & INFINITY_FLAG) != 0;
    303   }
    304 
    305   @Override
    306   public boolean isNaN() {
    307     return (flags & NAN_FLAG) != 0;
    308   }
    309 
    310   @Override
    311   public boolean isZero() {
    312     return precision == 0;
    313   }
    314 
    315   public void setToInt(int n) {
    316     setBcdToZero();
    317     flags = 0;
    318     if (n < 0) {
    319       flags |= NEGATIVE_FLAG;
    320       n = -n;
    321     }
    322     if (n != 0) {
    323       _setToInt(n);
    324       compact();
    325     }
    326   }
    327 
    328   private void _setToInt(int n) {
    329     if (n == Integer.MIN_VALUE) {
    330       readLongToBcd(-(long) n);
    331     } else {
    332       readIntToBcd(n);
    333     }
    334   }
    335 
    336   public void setToLong(long n) {
    337     setBcdToZero();
    338     flags = 0;
    339     if (n < 0) {
    340       flags |= NEGATIVE_FLAG;
    341       n = -n;
    342     }
    343     if (n != 0) {
    344       _setToLong(n);
    345       compact();
    346     }
    347   }
    348 
    349   private void _setToLong(long n) {
    350     if (n == Long.MIN_VALUE) {
    351       readBigIntegerToBcd(BigInteger.valueOf(n).negate());
    352     } else if (n <= Integer.MAX_VALUE) {
    353       readIntToBcd((int) n);
    354     } else {
    355       readLongToBcd(n);
    356     }
    357   }
    358 
    359   public void setToBigInteger(BigInteger n) {
    360     setBcdToZero();
    361     flags = 0;
    362     if (n.signum() == -1) {
    363       flags |= NEGATIVE_FLAG;
    364       n = n.negate();
    365     }
    366     if (n.signum() != 0) {
    367       _setToBigInteger(n);
    368       compact();
    369     }
    370   }
    371 
    372   private void _setToBigInteger(BigInteger n) {
    373     if (n.bitLength() < 32) {
    374       readIntToBcd(n.intValue());
    375     } else if (n.bitLength() < 64) {
    376       readLongToBcd(n.longValue());
    377     } else {
    378       readBigIntegerToBcd(n);
    379     }
    380   }
    381 
    382   /**
    383    * Sets the internal BCD state to represent the value in the given double.
    384    *
    385    * @param n The value to consume.
    386    */
    387   public void setToDouble(double n) {
    388     setBcdToZero();
    389     flags = 0;
    390     // Double.compare() handles +0.0 vs -0.0
    391     if (Double.compare(n, 0.0) < 0) {
    392       flags |= NEGATIVE_FLAG;
    393       n = -n;
    394     }
    395     if (Double.isNaN(n)) {
    396       flags |= NAN_FLAG;
    397     } else if (Double.isInfinite(n)) {
    398       flags |= INFINITY_FLAG;
    399     } else if (n != 0) {
    400       _setToDoubleFast(n);
    401       compact();
    402     }
    403   }
    404 
    405   private static final double[] DOUBLE_MULTIPLIERS = {
    406     1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16,
    407     1e17, 1e18, 1e19, 1e20, 1e21
    408   };
    409 
    410   /**
    411    * Uses double multiplication and division to get the number into integer space before converting
    412    * to digits. Since double arithmetic is inexact, the resulting digits may not be accurate.
    413    */
    414   private void _setToDoubleFast(double n) {
    415     isApproximate = true;
    416     origDouble = n;
    417     origDelta = 0;
    418 
    419     // NOTE: Unlike ICU4C, doubles are always IEEE 754 doubles.
    420     long ieeeBits = Double.doubleToLongBits(n);
    421     int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff;
    422 
    423     // Not all integers can be represented exactly for exponent > 52
    424     if (exponent <= 52 && (long) n == n) {
    425       _setToLong((long) n);
    426       return;
    427     }
    428 
    429     // 3.3219... is log2(10)
    430     int fracLength = (int) ((52 - exponent) / 3.32192809489);
    431     if (fracLength >= 0) {
    432       int i = fracLength;
    433       // 1e22 is the largest exact double.
    434       for (; i >= 22; i -= 22) n *= 1e22;
    435       n *= DOUBLE_MULTIPLIERS[i];
    436     } else {
    437       int i = fracLength;
    438       // 1e22 is the largest exact double.
    439       for (; i <= -22; i += 22) n /= 1e22;
    440       n /= DOUBLE_MULTIPLIERS[-i];
    441     }
    442     long result = Math.round(n);
    443     if (result != 0) {
    444       _setToLong(result);
    445       scale -= fracLength;
    446     }
    447   }
    448 
    449   /**
    450    * Uses Double.toString() to obtain an exact accurate representation of the double, overwriting it
    451    * into the BCD. This method can be called at any point after {@link #_setToDoubleFast} while
    452    * {@link #isApproximate} is still true.
    453    */
    454   private void convertToAccurateDouble() {
    455     double n = origDouble;
    456     assert n != 0;
    457     int delta = origDelta;
    458     setBcdToZero();
    459 
    460     // Call the slow oracle function (Double.toString in Java, sprintf in C++).
    461     String dstr = Double.toString(n);
    462 
    463     if (dstr.indexOf('E') != -1) {
    464       // Case 1: Exponential notation.
    465       assert dstr.indexOf('.') == 1;
    466       int expPos = dstr.indexOf('E');
    467       _setToLong(Long.parseLong(dstr.charAt(0) + dstr.substring(2, expPos)));
    468       scale += Integer.parseInt(dstr.substring(expPos + 1)) - (expPos - 1) + 1;
    469     } else if (dstr.charAt(0) == '0') {
    470       // Case 2: Fraction-only number.
    471       assert dstr.indexOf('.') == 1;
    472       _setToLong(Long.parseLong(dstr.substring(2)));
    473       scale += 2 - dstr.length();
    474     } else if (dstr.charAt(dstr.length() - 1) == '0') {
    475       // Case 3: Integer-only number.
    476       // Note: this path should not normally happen, because integer-only numbers are captured
    477       // before the approximate double logic is performed.
    478       assert dstr.indexOf('.') == dstr.length() - 2;
    479       assert dstr.length() - 2 <= 18;
    480       _setToLong(Long.parseLong(dstr.substring(0, dstr.length() - 2)));
    481       // no need to adjust scale
    482     } else {
    483       // Case 4: Number with both a fraction and an integer.
    484       int decimalPos = dstr.indexOf('.');
    485       _setToLong(Long.parseLong(dstr.substring(0, decimalPos) + dstr.substring(decimalPos + 1)));
    486       scale += decimalPos - dstr.length() + 1;
    487     }
    488 
    489     scale += delta;
    490     compact();
    491     explicitExactDouble = true;
    492   }
    493 
    494   /**
    495    * Whether this {@link DecimalQuantity_DualStorageBCD} has been explicitly converted to an exact double. true if
    496    * backed by a double that was explicitly converted via convertToAccurateDouble; false otherwise.
    497    * Used for testing.
    498    *
    499    * @deprecated This API is ICU internal only.
    500  * @hide draft / provisional / internal are hidden on Android
    501    */
    502   @Deprecated public boolean explicitExactDouble = false;
    503 
    504   /**
    505    * Sets the internal BCD state to represent the value in the given BigDecimal.
    506    *
    507    * @param n The value to consume.
    508    */
    509   @Override
    510   public void setToBigDecimal(BigDecimal n) {
    511     setBcdToZero();
    512     flags = 0;
    513     if (n.signum() == -1) {
    514       flags |= NEGATIVE_FLAG;
    515       n = n.negate();
    516     }
    517     if (n.signum() != 0) {
    518       _setToBigDecimal(n);
    519       compact();
    520     }
    521   }
    522 
    523   private void _setToBigDecimal(BigDecimal n) {
    524     int fracLength = n.scale();
    525     n = n.scaleByPowerOfTen(fracLength);
    526     BigInteger bi = n.toBigInteger();
    527     _setToBigInteger(bi);
    528     scale -= fracLength;
    529   }
    530 
    531   /**
    532    * Returns a long approximating the internal BCD. A long can only represent the integral part of
    533    * the number.
    534    *
    535    * @return A double representation of the internal BCD.
    536    */
    537   protected long toLong() {
    538     long result = 0L;
    539     for (int magnitude = scale + precision - 1; magnitude >= 0; magnitude--) {
    540       result = result * 10 + getDigitPos(magnitude - scale);
    541     }
    542     return result;
    543   }
    544 
    545   /**
    546    * This returns a long representing the fraction digits of the number, as required by PluralRules.
    547    * For example, if we represent the number "1.20" (including optional and required digits), then
    548    * this function returns "20" if includeTrailingZeros is true or "2" if false.
    549    */
    550   protected long toFractionLong(boolean includeTrailingZeros) {
    551     long result = 0L;
    552     int magnitude = -1;
    553     for (;
    554         (magnitude >= scale || (includeTrailingZeros && magnitude >= rReqPos))
    555             && magnitude >= rOptPos;
    556         magnitude--) {
    557       result = result * 10 + getDigitPos(magnitude - scale);
    558     }
    559     return result;
    560   }
    561 
    562   /**
    563    * Returns a double approximating the internal BCD. The double may not retain all of the
    564    * information encoded in the BCD if the BCD represents a number out of range of a double.
    565    *
    566    * @return A double representation of the internal BCD.
    567    */
    568   @Override
    569   public double toDouble() {
    570     if (isApproximate) {
    571       return toDoubleFromOriginal();
    572     }
    573 
    574     if (isNaN()) {
    575       return Double.NaN;
    576     } else if (isInfinite()) {
    577       return isNegative() ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
    578     }
    579 
    580     long tempLong = 0L;
    581     int lostDigits = precision - Math.min(precision, 17);
    582     for (int shift = precision - 1; shift >= lostDigits; shift--) {
    583       tempLong = tempLong * 10 + getDigitPos(shift);
    584     }
    585     double result = tempLong;
    586     int _scale = scale + lostDigits;
    587     if (_scale >= 0) {
    588       // 1e22 is the largest exact double.
    589       int i = _scale;
    590       for (; i >= 22; i -= 22) result *= 1e22;
    591       result *= DOUBLE_MULTIPLIERS[i];
    592     } else {
    593       // 1e22 is the largest exact double.
    594       int i = _scale;
    595       for (; i <= -22; i += 22) result /= 1e22;
    596       result /= DOUBLE_MULTIPLIERS[-i];
    597     }
    598     if (isNegative()) result = -result;
    599     return result;
    600   }
    601 
    602   @Override
    603   public BigDecimal toBigDecimal() {
    604     if (isApproximate) {
    605       // Converting to a BigDecimal requires Double.toString().
    606       convertToAccurateDouble();
    607     }
    608     return bcdToBigDecimal();
    609   }
    610 
    611   protected double toDoubleFromOriginal() {
    612     double result = origDouble;
    613     int delta = origDelta;
    614     if (delta >= 0) {
    615       // 1e22 is the largest exact double.
    616       for (; delta >= 22; delta -= 22) result *= 1e22;
    617       result *= DOUBLE_MULTIPLIERS[delta];
    618     } else {
    619       // 1e22 is the largest exact double.
    620       for (; delta <= -22; delta += 22) result /= 1e22;
    621       result /= DOUBLE_MULTIPLIERS[-delta];
    622     }
    623     if (isNegative()) result *= -1;
    624     return result;
    625   }
    626 
    627   private static int safeSubtract(int a, int b) {
    628     int diff = a - b;
    629     if (b < 0 && diff < a) return Integer.MAX_VALUE;
    630     if (b > 0 && diff > a) return Integer.MIN_VALUE;
    631     return diff;
    632   }
    633 
    634   private static final int SECTION_LOWER_EDGE = -1;
    635   private static final int SECTION_UPPER_EDGE = -2;
    636 
    637   @Override
    638   public void roundToMagnitude(int magnitude, MathContext mathContext) {
    639     // The position in the BCD at which rounding will be performed; digits to the right of position
    640     // will be rounded away.
    641     // TODO: Andy: There was a test failure because of integer overflow here. Should I do
    642     // "safe subtraction" everywhere in the code?  What's the nicest way to do it?
    643     int position = safeSubtract(magnitude, scale);
    644 
    645     // Enforce the number of digits required by the MathContext.
    646     int _mcPrecision = mathContext.getPrecision();
    647     if (magnitude == Integer.MAX_VALUE
    648         || (_mcPrecision > 0 && precision - position > _mcPrecision)) {
    649       position = precision - _mcPrecision;
    650     }
    651 
    652     if (position <= 0 && !isApproximate) {
    653       // All digits are to the left of the rounding magnitude.
    654     } else if (precision == 0) {
    655       // No rounding for zero.
    656     } else {
    657       // Perform rounding logic.
    658       // "leading" = most significant digit to the right of rounding
    659       // "trailing" = least significant digit to the left of rounding
    660       byte leadingDigit = getDigitPos(safeSubtract(position, 1));
    661       byte trailingDigit = getDigitPos(position);
    662 
    663       // Compute which section of the number we are in.
    664       // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles)
    665       // LOWER means we are between the bottom edge and the midpoint, like 1.391
    666       // MIDPOINT means we are exactly in the middle, like 1.500
    667       // UPPER means we are between the midpoint and the top edge, like 1.916
    668       int section = RoundingUtils.SECTION_MIDPOINT;
    669       if (!isApproximate) {
    670         if (leadingDigit < 5) {
    671           section = RoundingUtils.SECTION_LOWER;
    672         } else if (leadingDigit > 5) {
    673           section = RoundingUtils.SECTION_UPPER;
    674         } else {
    675           for (int p = safeSubtract(position, 2); p >= 0; p--) {
    676             if (getDigitPos(p) != 0) {
    677               section = RoundingUtils.SECTION_UPPER;
    678               break;
    679             }
    680           }
    681         }
    682       } else {
    683         int p = safeSubtract(position, 2);
    684         int minP = Math.max(0, precision - 14);
    685         if (leadingDigit == 0) {
    686           section = SECTION_LOWER_EDGE;
    687           for (; p >= minP; p--) {
    688             if (getDigitPos(p) != 0) {
    689               section = RoundingUtils.SECTION_LOWER;
    690               break;
    691             }
    692           }
    693         } else if (leadingDigit == 4) {
    694           for (; p >= minP; p--) {
    695             if (getDigitPos(p) != 9) {
    696               section = RoundingUtils.SECTION_LOWER;
    697               break;
    698             }
    699           }
    700         } else if (leadingDigit == 5) {
    701           for (; p >= minP; p--) {
    702             if (getDigitPos(p) != 0) {
    703               section = RoundingUtils.SECTION_UPPER;
    704               break;
    705             }
    706           }
    707         } else if (leadingDigit == 9) {
    708           section = SECTION_UPPER_EDGE;
    709           for (; p >= minP; p--) {
    710             if (getDigitPos(p) != 9) {
    711               section = RoundingUtils.SECTION_UPPER;
    712               break;
    713             }
    714           }
    715         } else if (leadingDigit < 5) {
    716           section = RoundingUtils.SECTION_LOWER;
    717         } else {
    718           section = RoundingUtils.SECTION_UPPER;
    719         }
    720 
    721         boolean roundsAtMidpoint =
    722             RoundingUtils.roundsAtMidpoint(mathContext.getRoundingMode().ordinal());
    723         if (safeSubtract(position, 1) < precision - 14
    724             || (roundsAtMidpoint && section == RoundingUtils.SECTION_MIDPOINT)
    725             || (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) {
    726           // Oops! This means that we have to get the exact representation of the double, because
    727           // the zone of uncertainty is along the rounding boundary.
    728           convertToAccurateDouble();
    729           roundToMagnitude(magnitude, mathContext); // start over
    730           return;
    731         }
    732 
    733         // Turn off the approximate double flag, since the value is now confirmed to be exact.
    734         isApproximate = false;
    735         origDouble = 0.0;
    736         origDelta = 0;
    737 
    738         if (position <= 0) {
    739           // All digits are to the left of the rounding magnitude.
    740           return;
    741         }
    742 
    743         // Good to continue rounding.
    744         if (section == SECTION_LOWER_EDGE) section = RoundingUtils.SECTION_LOWER;
    745         if (section == SECTION_UPPER_EDGE) section = RoundingUtils.SECTION_UPPER;
    746       }
    747 
    748       boolean roundDown =
    749           RoundingUtils.getRoundingDirection(
    750               (trailingDigit % 2) == 0,
    751               isNegative(),
    752               section,
    753               mathContext.getRoundingMode().ordinal(),
    754               this);
    755 
    756       // Perform truncation
    757       if (position >= precision) {
    758         setBcdToZero();
    759         scale = magnitude;
    760       } else {
    761         shiftRight(position);
    762       }
    763 
    764       // Bubble the result to the higher digits
    765       if (!roundDown) {
    766         if (trailingDigit == 9) {
    767           int bubblePos = 0;
    768           // Note: in the long implementation, the most digits BCD can have at this point is 15,
    769           // so bubblePos <= 15 and getDigitPos(bubblePos) is safe.
    770           for (; getDigitPos(bubblePos) == 9; bubblePos++) {}
    771           shiftRight(bubblePos); // shift off the trailing 9s
    772         }
    773         byte digit0 = getDigitPos(0);
    774         assert digit0 != 9;
    775         setDigitPos(0, (byte) (digit0 + 1));
    776         precision += 1; // in case an extra digit got added
    777       }
    778 
    779       compact();
    780     }
    781   }
    782 
    783   @Override
    784   public void roundToInfinity() {
    785     if (isApproximate) {
    786       convertToAccurateDouble();
    787     }
    788   }
    789 
    790   /**
    791    * Appends a digit, optionally with one or more leading zeros, to the end of the value represented
    792    * by this DecimalQuantity.
    793    *
    794    * <p>The primary use of this method is to construct numbers during a parsing loop. It allows
    795    * parsing to take advantage of the digit list infrastructure primarily designed for formatting.
    796    *
    797    * @param value The digit to append.
    798    * @param leadingZeros The number of zeros to append before the digit. For example, if the value
    799    *     in this instance starts as 12.3, and you append a 4 with 1 leading zero, the value becomes
    800    *     12.304.
    801    * @param appendAsInteger If true, increase the magnitude of existing digits to make room for the
    802    *     new digit. If false, append to the end like a fraction digit. If true, there must not be
    803    *     any fraction digits already in the number.
    804    * @deprecated This API is ICU internal only.
    805  * @hide draft / provisional / internal are hidden on Android
    806    */
    807   @Deprecated
    808   public void appendDigit(byte value, int leadingZeros, boolean appendAsInteger) {
    809     assert leadingZeros >= 0;
    810 
    811     // Zero requires special handling to maintain the invariant that the least-significant digit
    812     // in the BCD is nonzero.
    813     if (value == 0) {
    814       if (appendAsInteger && precision != 0) {
    815         scale += leadingZeros + 1;
    816       }
    817       return;
    818     }
    819 
    820     // Deal with trailing zeros
    821     if (scale > 0) {
    822       leadingZeros += scale;
    823       if (appendAsInteger) {
    824         scale = 0;
    825       }
    826     }
    827 
    828     // Append digit
    829     shiftLeft(leadingZeros + 1);
    830     setDigitPos(0, value);
    831 
    832     // Fix scale if in integer mode
    833     if (appendAsInteger) {
    834       scale += leadingZeros + 1;
    835     }
    836   }
    837 
    838   @Override
    839   public String toPlainString() {
    840       // NOTE: This logic is duplicated between here and DecimalQuantity_SimpleStorage.
    841       StringBuilder sb = new StringBuilder();
    842       if (isNegative()) {
    843           sb.append('-');
    844       }
    845       for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
    846         sb.append(getDigit(m));
    847         if (m == 0) sb.append('.');
    848       }
    849       return sb.toString();
    850   }
    851 
    852   /**
    853    * Returns a single digit from the BCD list. No internal state is changed by calling this method.
    854    *
    855    * @param position The position of the digit to pop, counted in BCD units from the least
    856    *     significant digit. If outside the range supported by the implementation, zero is returned.
    857    * @return The digit at the specified location.
    858    */
    859   protected abstract byte getDigitPos(int position);
    860 
    861   /**
    862    * Sets the digit in the BCD list. This method only sets the digit; it is the caller's
    863    * responsibility to call {@link #compact} after setting the digit.
    864    *
    865    * @param position The position of the digit to pop, counted in BCD units from the least
    866    *     significant digit. If outside the range supported by the implementation, an AssertionError
    867    *     is thrown.
    868    * @param value The digit to set at the specified location.
    869    */
    870   protected abstract void setDigitPos(int position, byte value);
    871 
    872   /**
    873    * Adds zeros to the end of the BCD list. This will result in an invalid BCD representation; it is
    874    * the caller's responsibility to do further manipulation and then call {@link #compact}.
    875    *
    876    * @param numDigits The number of zeros to add.
    877    */
    878   protected abstract void shiftLeft(int numDigits);
    879 
    880   protected abstract void shiftRight(int numDigits);
    881 
    882   /**
    883    * Sets the internal representation to zero. Clears any values stored in scale, precision,
    884    * hasDouble, origDouble, origDelta, and BCD data.
    885    */
    886   protected abstract void setBcdToZero();
    887 
    888   /**
    889    * Sets the internal BCD state to represent the value in the given int. The int is guaranteed to
    890    * be either positive. The internal state is guaranteed to be empty when this method is called.
    891    *
    892    * @param n The value to consume.
    893    */
    894   protected abstract void readIntToBcd(int input);
    895 
    896   /**
    897    * Sets the internal BCD state to represent the value in the given long. The long is guaranteed to
    898    * be either positive. The internal state is guaranteed to be empty when this method is called.
    899    *
    900    * @param n The value to consume.
    901    */
    902   protected abstract void readLongToBcd(long input);
    903 
    904   /**
    905    * Sets the internal BCD state to represent the value in the given BigInteger. The BigInteger is
    906    * guaranteed to be positive, and it is guaranteed to be larger than Long.MAX_VALUE. The internal
    907    * state is guaranteed to be empty when this method is called.
    908    *
    909    * @param n The value to consume.
    910    */
    911   protected abstract void readBigIntegerToBcd(BigInteger input);
    912 
    913   /**
    914    * Returns a BigDecimal encoding the internal BCD value.
    915    *
    916    * @return A BigDecimal representation of the internal BCD.
    917    */
    918   protected abstract BigDecimal bcdToBigDecimal();
    919 
    920   protected abstract void copyBcdFrom(DecimalQuantity _other);
    921 
    922   /**
    923    * Removes trailing zeros from the BCD (adjusting the scale as required) and then computes the
    924    * precision. The precision is the number of digits in the number up through the greatest nonzero
    925    * digit.
    926    *
    927    * <p>This method must always be called when bcd changes in order for assumptions to be correct in
    928    * methods like {@link #fractionCount()}.
    929    */
    930   protected abstract void compact();
    931 }
    932