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