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