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.MathContext;
      7 import java.math.RoundingMode;
      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  * This is an older implementation of DecimalQuantity. A newer, faster implementation is
     17  * DecimalQuantity2. I kept this implementation around because it was useful for testing purposes
     18  * (being able to compare the output of one implementation with the other).
     19  *
     20  * <p>This class is NOT IMMUTABLE and NOT THREAD SAFE and is intended to be used by a single thread
     21  * to format a number through a formatter, which is thread-safe.
     22  */
     23 public class DecimalQuantity_SimpleStorage implements DecimalQuantity {
     24   // Four positions: left optional '(', left required '[', right required ']', right optional ')'.
     25   // These four positions determine which digits are displayed in the output string.  They do NOT
     26   // affect rounding.  These positions are internal-only and can be specified only by the public
     27   // endpoints like setFractionLength, setIntegerLength, and setSignificantDigits, among others.
     28   //
     29   //   * Digits between lReqPos and rReqPos are in the "required zone" and are always displayed.
     30   //   * Digits between lOptPos and rOptPos but outside the required zone are in the "optional zone"
     31   //     and are displayed unless they are trailing off the left or right edge of the number and
     32   //     have a numerical value of zero.  In order to be "trailing", the digits need to be beyond
     33   //     the decimal point in their respective directions.
     34   //   * Digits outside of the "optional zone" are never displayed.
     35   //
     36   // See the table below for illustrative examples.
     37   //
     38   // +---------+---------+---------+---------+------------+------------------------+--------------+
     39   // | lOptPos | lReqPos | rReqPos | rOptPos |   number   |        positions       | en-US string |
     40   // +---------+---------+---------+---------+------------+------------------------+--------------+
     41   // |    5    |    2    |   -1    |   -5    |   1234.567 |     ( 12[34.5]67  )    |   1,234.567  |
     42   // |    3    |    2    |   -1    |   -5    |   1234.567 |      1(2[34.5]67  )    |     234.567  |
     43   // |    3    |    2    |   -1    |   -2    |   1234.567 |      1(2[34.5]6)7      |     234.56   |
     44   // |    6    |    4    |    2    |   -5    | 123456789. |  123(45[67]89.     )   | 456,789.     |
     45   // |    6    |    4    |    2    |    1    | 123456789. |     123(45[67]8)9.     | 456,780.     |
     46   // |   -1    |   -1    |   -3    |   -4    | 0.123456   |     0.1([23]4)56       |        .0234 |
     47   // |    6    |    4    |   -2    |   -2    |     12.3   |     (  [  12.3 ])      |    0012.30   |
     48   // +---------+---------+---------+---------+------------+------------------------+--------------+
     49   //
     50   private int lOptPos = Integer.MAX_VALUE;
     51   private int lReqPos = 0;
     52   private int rReqPos = 0;
     53   private int rOptPos = Integer.MIN_VALUE;
     54 
     55   // Internally, attempt to use a long to store the number. A long can hold numbers between 18 and
     56   // 19 digits, covering the vast majority of use cases. We store three values: the long itself,
     57   // the "scale" of the long (the power of 10 represented by the rightmost digit in the long), and
     58   // the "precision" (the number of digits in the long). "primary" and "primaryScale" are the only
     59   // two variables that are required for representing the number in memory. "primaryPrecision" is
     60   // saved only for the sake of performance enhancements when performing certain operations. It can
     61   // always be re-computed from "primary" and "primaryScale".
     62   private long primary;
     63   private int primaryScale;
     64   private int primaryPrecision;
     65 
     66   // If the decimal can't fit into the long, fall back to a BigDecimal.
     67   private BigDecimal fallback;
     68 
     69   // Other properties
     70   private int flags;
     71   private static final int NEGATIVE_FLAG = 1;
     72   private static final int INFINITY_FLAG = 2;
     73   private static final int NAN_FLAG = 4;
     74   private static final long[] POWERS_OF_TEN = {
     75     1L,
     76     10L,
     77     100L,
     78     1000L,
     79     10000L,
     80     100000L,
     81     1000000L,
     82     10000000L,
     83     100000000L,
     84     1000000000L,
     85     10000000000L,
     86     100000000000L,
     87     1000000000000L,
     88     10000000000000L,
     89     100000000000000L,
     90     1000000000000000L,
     91     10000000000000000L,
     92     100000000000000000L,
     93     1000000000000000000L
     94   };
     95 
     96   @Override
     97   public int maxRepresentableDigits() {
     98     return Integer.MAX_VALUE;
     99   }
    100 
    101   public DecimalQuantity_SimpleStorage(long input) {
    102     if (input < 0) {
    103       setNegative(true);
    104       input *= -1;
    105     }
    106 
    107     primary = input;
    108     primaryScale = 0;
    109     primaryPrecision = computePrecision(primary);
    110     fallback = null;
    111   }
    112 
    113   /**
    114    * Creates a DecimalQuantity from the given double value. Internally attempts several strategies
    115    * for converting the double to an exact representation, falling back on a BigDecimal if it fails
    116    * to do so.
    117    *
    118    * @param input The double to represent by this DecimalQuantity.
    119    */
    120   public DecimalQuantity_SimpleStorage(double input) {
    121     if (input < 0) {
    122       setNegative(true);
    123       input *= -1;
    124     }
    125 
    126     // First try reading from IEEE bits. This is trivial only for doubles in [2^52, 2^64). If it
    127     // fails, we wasted only a few CPU cycles.
    128     long ieeeBits = Double.doubleToLongBits(input);
    129     int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff;
    130     if (exponent >= 52 && exponent <= 63) {
    131       // We can convert this double directly to a long.
    132       long mantissa = (ieeeBits & 0x000fffffffffffffL) + 0x0010000000000000L;
    133       primary = (mantissa << (exponent - 52));
    134       primaryScale = 0;
    135       primaryPrecision = computePrecision(primary);
    136       return;
    137     }
    138 
    139     // Now try parsing the string produced by Double.toString().
    140     String temp = Double.toString(input);
    141     try {
    142       if (temp.length() == 3 && temp.equals("0.0")) {
    143         // Case 1: Zero.
    144         primary = 0L;
    145         primaryScale = 0;
    146         primaryPrecision = 0;
    147       } else if (temp.indexOf('E') != -1) {
    148         // Case 2: Exponential notation.
    149         assert temp.indexOf('.') == 1;
    150         int expPos = temp.indexOf('E');
    151         primary = Long.parseLong(temp.charAt(0) + temp.substring(2, expPos));
    152         primaryScale = Integer.parseInt(temp.substring(expPos + 1)) - (expPos - 1) + 1;
    153         primaryPrecision = expPos - 1;
    154       } else if (temp.charAt(0) == '0') {
    155         // Case 3: Fraction-only number.
    156         assert temp.indexOf('.') == 1;
    157         primary = Long.parseLong(temp.substring(2)); // ignores leading zeros
    158         primaryScale = 2 - temp.length();
    159         primaryPrecision = computePrecision(primary);
    160       } else if (temp.charAt(temp.length() - 1) == '0') {
    161         // Case 4: Integer-only number.
    162         assert temp.indexOf('.') == temp.length() - 2;
    163         int rightmostNonzeroDigitIndex = temp.length() - 3;
    164         while (temp.charAt(rightmostNonzeroDigitIndex) == '0') {
    165           rightmostNonzeroDigitIndex -= 1;
    166         }
    167         primary = Long.parseLong(temp.substring(0, rightmostNonzeroDigitIndex + 1));
    168         primaryScale = temp.length() - rightmostNonzeroDigitIndex - 3;
    169         primaryPrecision = rightmostNonzeroDigitIndex + 1;
    170       } else if (temp.equals("Infinity")) {
    171         // Case 5: Infinity.
    172         primary = 0;
    173         setInfinity(true);
    174       } else if (temp.equals("NaN")) {
    175         // Case 6: NaN.
    176         primary = 0;
    177         setNaN(true);
    178       } else {
    179         // Case 7: Number with both a fraction and an integer.
    180         int decimalPos = temp.indexOf('.');
    181         primary = Long.parseLong(temp.substring(0, decimalPos) + temp.substring(decimalPos + 1));
    182         primaryScale = decimalPos - temp.length() + 1;
    183         primaryPrecision = temp.length() - 1;
    184       }
    185     } catch (NumberFormatException e) {
    186       // The digits of the double can't fit into the long.
    187       primary = -1;
    188       fallback = new BigDecimal(temp);
    189     }
    190   }
    191 
    192   static final double LOG_2_OF_TEN = 3.32192809489;
    193 
    194   public DecimalQuantity_SimpleStorage(double input, boolean fast) {
    195     if (input < 0) {
    196       setNegative(true);
    197       input *= -1;
    198     }
    199 
    200     // Our strategy is to read all digits that are *guaranteed* to be valid without delving into
    201     // the IEEE rounding rules.  This strategy might not end up with a perfect representation of
    202     // the fractional part of the double.
    203     long ieeeBits = Double.doubleToLongBits(input);
    204     int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff;
    205     long mantissa = (ieeeBits & 0x000fffffffffffffL) + 0x0010000000000000L;
    206     if (exponent > 63) {
    207       throw new IllegalArgumentException(); // FIXME
    208     } else if (exponent >= 52) {
    209       primary = (mantissa << (exponent - 52));
    210       primaryScale = 0;
    211       primaryPrecision = computePrecision(primary);
    212       return;
    213     } else if (exponent >= 0) {
    214       int shift = 52 - exponent;
    215       primary = (mantissa >> shift); // integer part
    216       int fractionCount = (int) (shift / LOG_2_OF_TEN);
    217       long fraction = (mantissa - (primary << shift)) + 1L; // TODO: Explain the +1L
    218       primary *= POWERS_OF_TEN[fractionCount];
    219       for (int i = 0; i < fractionCount; i++) {
    220         long times10 = (fraction * 10L);
    221         long digit = times10 >> shift;
    222         assert digit >= 0 && digit < 10;
    223         primary += digit * POWERS_OF_TEN[fractionCount - i - 1];
    224         fraction = times10 & ((1L << shift) - 1);
    225       }
    226       primaryScale = -fractionCount;
    227       primaryPrecision = computePrecision(primary);
    228     } else {
    229       throw new IllegalArgumentException(); // FIXME
    230     }
    231   }
    232 
    233   public DecimalQuantity_SimpleStorage(BigDecimal decimal) {
    234     setToBigDecimal(decimal);
    235   }
    236 
    237   public DecimalQuantity_SimpleStorage(DecimalQuantity_SimpleStorage other) {
    238     copyFrom(other);
    239   }
    240 
    241   @Override
    242   public void setToBigDecimal(BigDecimal decimal) {
    243     if (decimal.compareTo(BigDecimal.ZERO) < 0) {
    244       setNegative(true);
    245       decimal = decimal.negate();
    246     }
    247 
    248     primary = -1;
    249     if (decimal.compareTo(BigDecimal.ZERO) == 0) {
    250       fallback = BigDecimal.ZERO;
    251     } else {
    252       fallback = decimal;
    253     }
    254   }
    255 
    256   @Override
    257   public DecimalQuantity_SimpleStorage createCopy() {
    258     return new DecimalQuantity_SimpleStorage(this);
    259   }
    260 
    261   /**
    262    * Make the internal state of this DecimalQuantity equal to another DecimalQuantity.
    263    *
    264    * @param other The template DecimalQuantity. All properties from this DecimalQuantity will be
    265    *     copied into this DecimalQuantity.
    266    */
    267   @Override
    268   public void copyFrom(DecimalQuantity other) {
    269     // TODO: Check before casting
    270     DecimalQuantity_SimpleStorage _other = (DecimalQuantity_SimpleStorage) other;
    271     lOptPos = _other.lOptPos;
    272     lReqPos = _other.lReqPos;
    273     rReqPos = _other.rReqPos;
    274     rOptPos = _other.rOptPos;
    275     primary = _other.primary;
    276     primaryScale = _other.primaryScale;
    277     primaryPrecision = _other.primaryPrecision;
    278     fallback = _other.fallback;
    279     flags = _other.flags;
    280   }
    281 
    282   @Override
    283   public long getPositionFingerprint() {
    284     long fingerprint = 0;
    285     fingerprint ^= lOptPos;
    286     fingerprint ^= (lReqPos << 16);
    287     fingerprint ^= ((long) rReqPos << 32);
    288     fingerprint ^= ((long) rOptPos << 48);
    289     return fingerprint;
    290   }
    291 
    292   /**
    293    * Utility method to compute the number of digits ("precision") in a long.
    294    *
    295    * @param input The long (which can't contain more than 19 digits).
    296    * @return The precision of the long.
    297    */
    298   private static int computePrecision(long input) {
    299     int precision = 0;
    300     while (input > 0) {
    301       input /= 10;
    302       precision++;
    303     }
    304     return precision;
    305   }
    306 
    307   /**
    308    * Changes the internal representation from a long to a BigDecimal. Used only for operations that
    309    * don't support longs.
    310    */
    311   private void convertToBigDecimal() {
    312     if (primary == -1) {
    313       return;
    314     }
    315 
    316     fallback = new BigDecimal(primary).scaleByPowerOfTen(primaryScale);
    317     primary = -1;
    318   }
    319 
    320   @Override
    321   public void setIntegerLength(int minInt, int maxInt) {
    322     // Graceful failures for bogus input
    323     minInt = Math.max(0, minInt);
    324     maxInt = Math.max(0, maxInt);
    325 
    326     // The minima must be less than or equal to the maxima
    327     if (maxInt < minInt) {
    328       minInt = maxInt;
    329     }
    330 
    331     // Save values into internal state
    332     // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
    333     lOptPos = maxInt;
    334     lReqPos = minInt;
    335   }
    336 
    337   @Override
    338   public void setFractionLength(int minFrac, int maxFrac) {
    339     // Graceful failures for bogus input
    340     minFrac = Math.max(0, minFrac);
    341     maxFrac = Math.max(0, maxFrac);
    342 
    343     // The minima must be less than or equal to the maxima
    344     if (maxFrac < minFrac) {
    345       minFrac = maxFrac;
    346     }
    347 
    348     // Save values into internal state
    349     // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
    350     rReqPos = -minFrac;
    351     rOptPos = -maxFrac;
    352   }
    353 
    354   @Override
    355   public void roundToIncrement(BigDecimal roundingInterval, MathContext mathContext) {
    356     BigDecimal d =
    357         (primary == -1) ? fallback : new BigDecimal(primary).scaleByPowerOfTen(primaryScale);
    358     if (isNegative()) d = d.negate();
    359     d = d.divide(roundingInterval, 0, mathContext.getRoundingMode()).multiply(roundingInterval);
    360     if (isNegative()) d = d.negate();
    361     fallback = d;
    362     primary = -1;
    363   }
    364 
    365   @Override
    366   public void roundToMagnitude(int roundingMagnitude, MathContext mathContext) {
    367     if (roundingMagnitude < -1000) {
    368       roundToInfinity();
    369       return;
    370     }
    371     if (primary == -1) {
    372       if (isNegative()) fallback = fallback.negate();
    373       fallback = fallback.setScale(-roundingMagnitude, mathContext.getRoundingMode());
    374       if (isNegative()) fallback = fallback.negate();
    375       // Enforce the math context.
    376       fallback = fallback.round(mathContext);
    377     } else {
    378       int relativeScale = primaryScale - roundingMagnitude;
    379       if (relativeScale < -18) {
    380         // No digits will remain after rounding the number.
    381         primary = 0L;
    382         primaryScale = roundingMagnitude;
    383         primaryPrecision = 0;
    384       } else if (relativeScale < 0) {
    385         // This is the harder case, when we need to perform the rounding logic.
    386         // First check if the rightmost digits are already zero, where we can skip rounding.
    387         if ((primary % POWERS_OF_TEN[0 - relativeScale]) == 0) {
    388           // No rounding is necessary.
    389         } else {
    390           // TODO: Make this more efficient. Temporarily, convert to a BigDecimal and back again.
    391           BigDecimal temp = new BigDecimal(primary).scaleByPowerOfTen(primaryScale);
    392           if (isNegative()) temp = temp.negate();
    393           temp = temp.setScale(-roundingMagnitude, mathContext.getRoundingMode());
    394           if (isNegative()) temp = temp.negate();
    395           temp = temp.scaleByPowerOfTen(-roundingMagnitude);
    396           primary = temp.longValueExact(); // should never throw
    397           primaryScale = roundingMagnitude;
    398           primaryPrecision = computePrecision(primary);
    399         }
    400       } else {
    401         // No rounding is necessary. All digits are to the left of the rounding magnitude.
    402       }
    403       // Enforce the math context.
    404       primary = new BigDecimal(primary).round(mathContext).longValueExact();
    405       primaryPrecision = computePrecision(primary);
    406     }
    407   }
    408 
    409   @Override
    410   public void roundToInfinity() {
    411     // noop
    412   }
    413 
    414   /**
    415    * Multiply the internal number by the specified multiplicand. This method forces the internal
    416    * representation into a BigDecimal. If you are multiplying by a power of 10, use {@link
    417    * #adjustMagnitude} instead.
    418    *
    419    * @param multiplicand The number to be passed to {@link BigDecimal#multiply}.
    420    */
    421   @Override
    422   public void multiplyBy(BigDecimal multiplicand) {
    423     convertToBigDecimal();
    424     fallback = fallback.multiply(multiplicand);
    425     if (fallback.compareTo(BigDecimal.ZERO) < 0) {
    426       setNegative(!isNegative());
    427       fallback = fallback.negate();
    428     }
    429   }
    430 
    431   /**
    432    * Divide the internal number by the specified quotient. This method forces the internal
    433    * representation into a BigDecimal. If you are dividing by a power of 10, use {@link
    434    * #adjustMagnitude} instead.
    435    *
    436    * @param divisor The number to be passed to {@link BigDecimal#divide}.
    437    * @param scale The scale of the final rounded number. More negative means more decimal places.
    438    * @param mathContext The math context to use if rounding is necessary.
    439    */
    440   @SuppressWarnings("unused")
    441   private void divideBy(BigDecimal divisor, int scale, MathContext mathContext) {
    442     convertToBigDecimal();
    443     // Negate the scale because BigDecimal's scale is defined as the inverse of our scale
    444     fallback = fallback.divide(divisor, -scale, mathContext.getRoundingMode());
    445     if (fallback.compareTo(BigDecimal.ZERO) < 0) {
    446       setNegative(!isNegative());
    447       fallback = fallback.negate();
    448     }
    449   }
    450 
    451   @Override
    452   public boolean isZero() {
    453     if (primary == -1) {
    454       return fallback.compareTo(BigDecimal.ZERO) == 0;
    455     } else {
    456       return primary == 0;
    457     }
    458   }
    459 
    460   /** @return The power of ten of the highest digit represented by this DecimalQuantity */
    461   @Override
    462   public int getMagnitude() throws ArithmeticException {
    463     int scale = (primary == -1) ? scaleBigDecimal(fallback) : primaryScale;
    464     int precision = (primary == -1) ? precisionBigDecimal(fallback) : primaryPrecision;
    465     if (precision == 0) {
    466       throw new ArithmeticException("Magnitude is not well-defined for zero");
    467     } else {
    468       return scale + precision - 1;
    469     }
    470   }
    471 
    472   /**
    473    * Changes the magnitude of this DecimalQuantity. If the indices of the represented digits had been
    474    * previously specified, those indices are moved relative to the DecimalQuantity.
    475    *
    476    * <p>This method does NOT perform rounding.
    477    *
    478    * @param delta The number of powers of ten to shift (positive shifts to the left).
    479    */
    480   @Override
    481   public void adjustMagnitude(int delta) {
    482     if (primary == -1) {
    483       fallback = fallback.scaleByPowerOfTen(delta);
    484     } else {
    485       primaryScale = addOrMaxValue(primaryScale, delta);
    486     }
    487   }
    488 
    489   private static int addOrMaxValue(int a, int b) {
    490     // Check for overflow, and return min/max value if overflow occurs.
    491     if (b < 0 && a + b > a) {
    492       return Integer.MIN_VALUE;
    493     } else if (b > 0 && a + b < a) {
    494       return Integer.MAX_VALUE;
    495     }
    496     return a + b;
    497   }
    498 
    499   /** @return If the number represented by this DecimalQuantity is less than zero */
    500   @Override
    501   public boolean isNegative() {
    502     return (flags & NEGATIVE_FLAG) != 0;
    503   }
    504 
    505   private void setNegative(boolean isNegative) {
    506     flags = (flags & (~NEGATIVE_FLAG)) | (isNegative ? NEGATIVE_FLAG : 0);
    507   }
    508 
    509   @Override
    510   public boolean isInfinite() {
    511     return (flags & INFINITY_FLAG) != 0;
    512   }
    513 
    514   private void setInfinity(boolean isInfinity) {
    515     flags = (flags & (~INFINITY_FLAG)) | (isInfinity ? INFINITY_FLAG : 0);
    516   }
    517 
    518   @Override
    519   public boolean isNaN() {
    520     return (flags & NAN_FLAG) != 0;
    521   }
    522 
    523   private void setNaN(boolean isNaN) {
    524     flags = (flags & (~NAN_FLAG)) | (isNaN ? NAN_FLAG : 0);
    525   }
    526 
    527   /**
    528    * Returns a representation of this DecimalQuantity as a double, with possible loss of information.
    529    */
    530   @Override
    531   public double toDouble() {
    532     double result;
    533     if (primary == -1) {
    534       result = fallback.doubleValue();
    535     } else {
    536       // TODO: Make this more efficient
    537       result = primary;
    538       for (int i = 0; i < primaryScale; i++) {
    539         result *= 10.;
    540       }
    541       for (int i = 0; i > primaryScale; i--) {
    542         result /= 10.;
    543       }
    544     }
    545     return isNegative() ? -result : result;
    546   }
    547 
    548   @Override
    549   public BigDecimal toBigDecimal() {
    550     BigDecimal result;
    551     if (primary != -1) {
    552       result = new BigDecimal(primary).scaleByPowerOfTen(primaryScale);
    553     } else {
    554       result = fallback;
    555     }
    556     return isNegative() ? result.negate() : result;
    557   }
    558 
    559   @Override
    560   public StandardPlural getStandardPlural(PluralRules rules) {
    561     if (rules == null) {
    562       // Fail gracefully if the user didn't provide a PluralRules
    563       return StandardPlural.OTHER;
    564     } else {
    565       // TODO: Avoid converting to a double for the sake of PluralRules
    566       String ruleString = rules.select(toDouble());
    567       return StandardPlural.orOtherFromString(ruleString);
    568     }
    569   }
    570 
    571   @Override
    572   public double getPluralOperand(Operand operand) {
    573     // TODO: This is a temporary hack.
    574     return new PluralRules.FixedDecimal(toDouble()).getPluralOperand(operand);
    575   }
    576 
    577   public boolean hasNextFraction() {
    578     if (rReqPos < 0) {
    579       // We are in the required zone.
    580       return true;
    581     } else if (rOptPos >= 0) {
    582       // We are in the forbidden zone.
    583       return false;
    584     } else {
    585       // We are in the optional zone.
    586       if (primary == -1) {
    587         return fallback.remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO) > 0;
    588       } else {
    589         if (primaryScale <= -19) {
    590           // The number is a fraction so small that it consists of only fraction digits.
    591           return primary > 0;
    592         } else if (primaryScale < 0) {
    593           // Check if we have a fraction part.
    594           long factor = POWERS_OF_TEN[0 - primaryScale];
    595           return ((primary % factor) != 0);
    596         } else {
    597           // The lowest digit in the long has magnitude greater than -1.
    598           return false;
    599         }
    600       }
    601     }
    602   }
    603 
    604   public byte nextFraction() {
    605     byte returnValue;
    606     if (primary == -1) {
    607       BigDecimal temp = fallback.multiply(BigDecimal.TEN);
    608       returnValue = temp.setScale(0, RoundingMode.FLOOR).remainder(BigDecimal.TEN).byteValue();
    609       fallback = fallback.setScale(0, RoundingMode.FLOOR).add(temp.remainder(BigDecimal.ONE));
    610     } else {
    611       if (primaryScale <= -20) {
    612         // The number is a fraction so small that it has no first fraction digit.
    613         primaryScale += 1;
    614         returnValue = 0;
    615       } else if (primaryScale < 0) {
    616         // Extract the fraction digit out of the middle of the long.
    617         long factor = POWERS_OF_TEN[0 - primaryScale - 1];
    618         long temp1 = primary / factor;
    619         long temp2 = primary % factor;
    620         returnValue = (byte) (temp1 % 10); // not necessarily nonzero
    621         primary = ((temp1 / 10) * factor) + temp2;
    622         primaryScale += 1;
    623         if (temp1 != 0) {
    624           primaryPrecision -= 1;
    625         }
    626       } else {
    627         // The lowest digit in the long has magnitude greater than -1.
    628         returnValue = 0;
    629       }
    630     }
    631 
    632     // Update digit brackets
    633     if (lOptPos < 0) {
    634       lOptPos += 1;
    635     }
    636     if (lReqPos < 0) {
    637       lReqPos += 1;
    638     }
    639     if (rReqPos < 0) {
    640       rReqPos += 1;
    641     }
    642     if (rOptPos < 0) {
    643       rOptPos += 1;
    644     }
    645 
    646     assert returnValue >= 0;
    647     return returnValue;
    648   }
    649 
    650   public boolean hasNextInteger() {
    651     if (lReqPos > 0) {
    652       // We are in the required zone.
    653       return true;
    654     } else if (lOptPos <= 0) {
    655       // We are in the forbidden zone.
    656       return false;
    657     } else {
    658       // We are in the optional zone.
    659       if (primary == -1) {
    660         return fallback.setScale(0, RoundingMode.FLOOR).compareTo(BigDecimal.ZERO) > 0;
    661       } else {
    662         if (primaryScale < -18) {
    663           // The number is a fraction so small that it has no integer part.
    664           return false;
    665         } else if (primaryScale < 0) {
    666           // Check if we have an integer part.
    667           long factor = POWERS_OF_TEN[0 - primaryScale];
    668           return ((primary % factor) != primary); // equivalent: ((primary / 10) != 0)
    669         } else {
    670           // The lowest digit in the long has magnitude of at least 0.
    671           return primary != 0;
    672         }
    673       }
    674     }
    675   }
    676 
    677   private int integerCount() {
    678     int digitsRemaining;
    679     if (primary == -1) {
    680       digitsRemaining = precisionBigDecimal(fallback) + scaleBigDecimal(fallback);
    681     } else {
    682       digitsRemaining = primaryPrecision + primaryScale;
    683     }
    684     return Math.min(Math.max(digitsRemaining, lReqPos), lOptPos);
    685   }
    686 
    687   private int fractionCount() {
    688     // TODO: This is temporary.
    689     DecimalQuantity_SimpleStorage copy = new DecimalQuantity_SimpleStorage(this);
    690     int fractionCount = 0;
    691     while (copy.hasNextFraction()) {
    692       copy.nextFraction();
    693       fractionCount++;
    694     }
    695     return fractionCount;
    696   }
    697 
    698   @Override
    699   public int getUpperDisplayMagnitude() {
    700     return integerCount() - 1;
    701   }
    702 
    703   @Override
    704   public int getLowerDisplayMagnitude() {
    705     return -fractionCount();
    706   }
    707 
    708   //  @Override
    709   //  public byte getIntegerDigit(int index) {
    710   //    return getDigitPos(index);
    711   //  }
    712   //
    713   //  @Override
    714   //  public byte getFractionDigit(int index) {
    715   //    return getDigitPos(-index - 1);
    716   //  }
    717 
    718   @Override
    719   public byte getDigit(int magnitude) {
    720     // TODO: This is temporary.
    721     DecimalQuantity_SimpleStorage copy = new DecimalQuantity_SimpleStorage(this);
    722     if (magnitude < 0) {
    723       for (int p = -1; p > magnitude; p--) {
    724         copy.nextFraction();
    725       }
    726       return copy.nextFraction();
    727     } else {
    728       for (int p = 0; p < magnitude; p++) {
    729         copy.nextInteger();
    730       }
    731       return copy.nextInteger();
    732     }
    733   }
    734 
    735   public byte nextInteger() {
    736     byte returnValue;
    737     if (primary == -1) {
    738       returnValue = fallback.setScale(0, RoundingMode.FLOOR).remainder(BigDecimal.TEN).byteValue();
    739       BigDecimal temp = fallback.divide(BigDecimal.TEN).setScale(0, RoundingMode.FLOOR);
    740       fallback = fallback.remainder(BigDecimal.ONE).add(temp);
    741     } else {
    742       if (primaryScale < -18) {
    743         // The number is a fraction so small that it has no integer part.
    744         returnValue = 0;
    745       } else if (primaryScale < 0) {
    746         // Extract the integer digit out of the middle of the long. In many ways, this is the heart
    747         // of the digit iterator algorithm.
    748         long factor = POWERS_OF_TEN[0 - primaryScale];
    749         if ((primary % factor) != primary) { // equivalent: ((primary / 10) != 0)
    750           returnValue = (byte) ((primary / factor) % 10);
    751           long temp = (primary / 10);
    752           primary = temp - (temp % factor) + (primary % factor);
    753           primaryPrecision -= 1;
    754         } else {
    755           returnValue = 0;
    756         }
    757       } else if (primaryScale == 0) {
    758         // Fast-path for primaryScale == 0 (otherwise equivalent to previous step).
    759         if (primary != 0) {
    760           returnValue = (byte) (primary % 10);
    761           primary /= 10;
    762           primaryPrecision -= 1;
    763         } else {
    764           returnValue = 0;
    765         }
    766       } else {
    767         // The lowest digit in the long has magnitude greater than 0.
    768         primaryScale -= 1;
    769         returnValue = 0;
    770       }
    771     }
    772 
    773     // Update digit brackets
    774     if (lOptPos > 0) {
    775       lOptPos -= 1;
    776     }
    777     if (lReqPos > 0) {
    778       lReqPos -= 1;
    779     }
    780     if (rReqPos > 0) {
    781       rReqPos -= 1;
    782     }
    783     if (rOptPos > 0) {
    784       rOptPos -= 1;
    785     }
    786 
    787     assert returnValue >= 0;
    788     return returnValue;
    789   }
    790 
    791   /**
    792    * Helper method to compute the precision of a BigDecimal by our definition of precision, which is
    793    * that the number zero gets precision zero.
    794    *
    795    * @param decimal The BigDecimal whose precision to compute.
    796    * @return The precision by our definition.
    797    */
    798   private static int precisionBigDecimal(BigDecimal decimal) {
    799     if (decimal.compareTo(BigDecimal.ZERO) == 0) {
    800       return 0;
    801     } else {
    802       return decimal.precision();
    803     }
    804   }
    805 
    806   /**
    807    * Helper method to compute the scale of a BigDecimal by our definition of scale, which is that
    808    * deeper fractions result in negative scales as opposed to positive scales.
    809    *
    810    * @param decimal The BigDecimal whose scale to compute.
    811    * @return The scale by our definition.
    812    */
    813   private static int scaleBigDecimal(BigDecimal decimal) {
    814     return -decimal.scale();
    815   }
    816 
    817   @Override
    818   public String toString() {
    819     StringBuilder sb = new StringBuilder();
    820     sb.append("<DecimalQuantity1 ");
    821     if (primary == -1) {
    822       sb.append(lOptPos > 1000 ? "max" : lOptPos);
    823       sb.append(":");
    824       sb.append(lReqPos);
    825       sb.append(":");
    826       sb.append(rReqPos);
    827       sb.append(":");
    828       sb.append(rOptPos < -1000 ? "min" : rOptPos);
    829       sb.append(" ");
    830       sb.append(fallback.toString());
    831     } else {
    832       String digits = Long.toString(primary);
    833       int iDec = digits.length() + primaryScale;
    834       int iLP = iDec - toRange(lOptPos, -1000, 1000);
    835       int iLB = iDec - toRange(lReqPos, -1000, 1000);
    836       int iRB = iDec - toRange(rReqPos, -1000, 1000);
    837       int iRP = iDec - toRange(rOptPos, -1000, 1000);
    838       iDec = Math.max(Math.min(iDec, digits.length() + 1), -1);
    839       iLP = Math.max(Math.min(iLP, digits.length() + 1), -1);
    840       iLB = Math.max(Math.min(iLB, digits.length() + 1), -1);
    841       iRB = Math.max(Math.min(iRB, digits.length() + 1), -1);
    842       iRP = Math.max(Math.min(iRP, digits.length() + 1), -1);
    843 
    844       for (int i = -1; i <= digits.length() + 1; i++) {
    845         if (i == iLP) sb.append('(');
    846         if (i == iLB) sb.append('[');
    847         if (i == iDec) sb.append('.');
    848         if (i == iRB) sb.append(']');
    849         if (i == iRP) sb.append(')');
    850         if (i >= 0 && i < digits.length()) sb.append(digits.charAt(i));
    851         else sb.append('\u00A0');
    852       }
    853     }
    854     sb.append(">");
    855     return sb.toString();
    856   }
    857 
    858   @Override
    859   public String toPlainString() {
    860       // NOTE: This logic is duplicated between here and DecimalQuantity_AbstractBCD.
    861       StringBuilder sb = new StringBuilder();
    862       if (isNegative()) {
    863           sb.append('-');
    864       }
    865       for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
    866         sb.append(getDigit(m));
    867         if (m == 0) sb.append('.');
    868       }
    869       return sb.toString();
    870   }
    871 
    872   private static int toRange(int i, int lo, int hi) {
    873     if (i < lo) {
    874       return lo;
    875     } else if (i > hi) {
    876       return hi;
    877     } else {
    878       return i;
    879     }
    880   }
    881 
    882   @Override
    883   public void populateUFieldPosition(FieldPosition fp) {
    884     if (fp instanceof UFieldPosition) {
    885       ((UFieldPosition) fp)
    886           .setFractionDigits((int) getPluralOperand(Operand.v), (long) getPluralOperand(Operand.f));
    887     }
    888   }
    889 }
    890