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