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