Home | History | Annotate | Download | only in number
      1 //  2017 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 package com.ibm.icu.impl.number;
      4 
      5 import java.math.BigDecimal;
      6 import java.math.BigInteger;
      7 
      8 public final class DecimalQuantity_ByteArrayBCD extends DecimalQuantity_AbstractBCD {
      9 
     10   /**
     11    * The BCD of the 16 digits of the number represented by this object. Every 4 bits of the long map
     12    * to one digit. For example, the number "12345" in BCD is "0x12345".
     13    *
     14    * <p>Whenever bcd changes internally, {@link #compact()} must be called, except in special cases
     15    * like setting the digit to zero.
     16    */
     17   private byte[] bcd = new byte[100];
     18 
     19   @Override
     20   public int maxRepresentableDigits() {
     21     return Integer.MAX_VALUE;
     22   }
     23 
     24   public DecimalQuantity_ByteArrayBCD(long input) {
     25     setToLong(input);
     26   }
     27 
     28   public DecimalQuantity_ByteArrayBCD(int input) {
     29     setToInt(input);
     30   }
     31 
     32   public DecimalQuantity_ByteArrayBCD(double input) {
     33     setToDouble(input);
     34   }
     35 
     36   public DecimalQuantity_ByteArrayBCD(BigInteger input) {
     37     setToBigInteger(input);
     38   }
     39 
     40   public DecimalQuantity_ByteArrayBCD(BigDecimal input) {
     41     setToBigDecimal(input);
     42   }
     43 
     44   public DecimalQuantity_ByteArrayBCD(DecimalQuantity_ByteArrayBCD other) {
     45     copyFrom(other);
     46   }
     47 
     48   @Override
     49   public DecimalQuantity createCopy() {
     50     return new DecimalQuantity_ByteArrayBCD(this);
     51   }
     52 
     53   @Override
     54   protected byte getDigitPos(int position) {
     55     if (position < 0 || position > precision) return 0;
     56     return bcd[position];
     57   }
     58 
     59   @Override
     60   protected void setDigitPos(int position, byte value) {
     61     assert position >= 0;
     62     ensureCapacity(position + 1);
     63     bcd[position] = value;
     64   }
     65 
     66   @Override
     67   protected void shiftLeft(int numDigits) {
     68     ensureCapacity(precision + numDigits);
     69     int i = precision + numDigits - 1;
     70     for (; i >= numDigits; i--) {
     71       bcd[i] = bcd[i - numDigits];
     72     }
     73     for (; i >= 0; i--) {
     74       bcd[i] = 0;
     75     }
     76     scale -= numDigits;
     77     precision += numDigits;
     78   }
     79 
     80   @Override
     81   protected void shiftRight(int numDigits) {
     82     int i = 0;
     83     for (; i < precision - numDigits; i++) {
     84       bcd[i] = bcd[i + numDigits];
     85     }
     86     for (; i < precision; i++) {
     87       bcd[i] = 0;
     88     }
     89     scale += numDigits;
     90     precision -= numDigits;
     91   }
     92 
     93   @Override
     94   protected void setBcdToZero() {
     95     for (int i = 0; i < precision; i++) {
     96       bcd[i] = (byte) 0;
     97     }
     98     scale = 0;
     99     precision = 0;
    100     isApproximate = false;
    101     origDouble = 0;
    102     origDelta = 0;
    103   }
    104 
    105   @Override
    106   protected void readIntToBcd(int n) {
    107     assert n != 0;
    108     int i = 0;
    109     for (; n != 0L; n /= 10L, i++) {
    110       bcd[i] = (byte) (n % 10);
    111     }
    112     scale = 0;
    113     precision = i;
    114   }
    115 
    116   private static final byte[] LONG_MIN_VALUE =
    117       new byte[] {8, 0, 8, 5, 7, 7, 4, 5, 8, 6, 3, 0, 2, 7, 3, 3, 2, 2, 9};
    118 
    119   @Override
    120   protected void readLongToBcd(long n) {
    121     assert n != 0;
    122     if (n == Long.MIN_VALUE) {
    123       // Can't consume via the normal path.
    124       System.arraycopy(LONG_MIN_VALUE, 0, bcd, 0, LONG_MIN_VALUE.length);
    125       scale = 0;
    126       precision = LONG_MIN_VALUE.length;
    127       return;
    128     }
    129     int i = 0;
    130     for (; n != 0L; n /= 10L, i++) {
    131       bcd[i] = (byte) (n % 10);
    132     }
    133     scale = 0;
    134     precision = i;
    135   }
    136 
    137   @Override
    138   protected void readBigIntegerToBcd(BigInteger n) {
    139     assert n.signum() != 0;
    140     int i = 0;
    141     for (; n.signum() != 0; i++) {
    142       BigInteger[] temp = n.divideAndRemainder(BigInteger.TEN);
    143       ensureCapacity(i + 1);
    144       bcd[i] = temp[1].byteValue();
    145       n = temp[0];
    146     }
    147     scale = 0;
    148     precision = i;
    149   }
    150 
    151   @Override
    152   protected BigDecimal bcdToBigDecimal() {
    153     // Converting to a string here is faster than doing BigInteger/BigDecimal arithmetic.
    154     return new BigDecimal(toDumbString());
    155   }
    156 
    157   private String toDumbString() {
    158     StringBuilder sb = new StringBuilder();
    159     if (isNegative()) sb.append('-');
    160     if (precision == 0) {
    161       sb.append('0');
    162       return sb.toString();
    163     }
    164     for (int i = precision - 1; i >= 0; i--) {
    165       sb.append(getDigitPos(i));
    166     }
    167     if (scale != 0) {
    168       sb.append('E');
    169       sb.append(scale);
    170     }
    171     return sb.toString();
    172   }
    173 
    174   @Override
    175   protected void compact() {
    176     // Special handling for 0
    177     boolean isZero = true;
    178     for (int i = 0; i < precision; i++) {
    179       if (bcd[i] != 0) {
    180         isZero = false;
    181         break;
    182       }
    183     }
    184     if (isZero) {
    185       scale = 0;
    186       precision = 0;
    187       return;
    188     }
    189 
    190     // Compact the number (remove trailing zeros)
    191     int delta = 0;
    192     for (; bcd[delta] == 0; delta++) ;
    193     shiftRight(delta);
    194 
    195     // Compute precision
    196     int leading = precision - 1;
    197     for (; leading >= 0 && bcd[leading] == 0; leading--) ;
    198     precision = leading + 1;
    199   }
    200 
    201   private void ensureCapacity(int capacity) {
    202     if (bcd.length >= capacity) return;
    203     byte[] bcd1 = new byte[capacity * 2];
    204     System.arraycopy(bcd, 0, bcd1, 0, bcd.length);
    205     bcd = bcd1;
    206   }
    207 
    208   @Override
    209   protected void copyBcdFrom(DecimalQuantity _other) {
    210     DecimalQuantity_ByteArrayBCD other = (DecimalQuantity_ByteArrayBCD) _other;
    211     System.arraycopy(other.bcd, 0, bcd, 0, bcd.length);
    212   }
    213 
    214   @Override
    215   public String toString() {
    216     StringBuilder sb = new StringBuilder();
    217     for (int i = 30; i >= 0; i--) {
    218       sb.append(bcd[i]);
    219     }
    220     return String.format(
    221         "<DecimalQuantity3 %s:%d:%d:%s %s%s%d>",
    222         (lOptPos > 1000 ? "max" : String.valueOf(lOptPos)),
    223         lReqPos,
    224         rReqPos,
    225         (rOptPos < -1000 ? "min" : String.valueOf(rOptPos)),
    226         sb,
    227         "E",
    228         scale);
    229   }
    230 }
    231