1// © 2017 and later: Unicode, Inc. and others. 2// License & terms of use: http://www.unicode.org/copyright.html#License 3package com.ibm.icu.impl.number; 4 5import java.math.BigDecimal; 6import java.math.BigInteger; 7 8public final class DecimalQuantity_64BitBCD 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 long bcd; 18 19 @Override 20 public int maxRepresentableDigits() { 21 return 16; 22 } 23 24 public DecimalQuantity_64BitBCD(long input) { 25 setToLong(input); 26 } 27 28 public DecimalQuantity_64BitBCD(int input) { 29 setToInt(input); 30 } 31 32 public DecimalQuantity_64BitBCD(double input) { 33 setToDouble(input); 34 } 35 36 public DecimalQuantity_64BitBCD(BigInteger input) { 37 setToBigInteger(input); 38 } 39 40 public DecimalQuantity_64BitBCD(BigDecimal input) { 41 setToBigDecimal(input); 42 } 43 44 public DecimalQuantity_64BitBCD(DecimalQuantity_64BitBCD other) { 45 copyFrom(other); 46 } 47 48 @Override 49 public DecimalQuantity createCopy() { 50 return new DecimalQuantity_64BitBCD(this); 51 } 52 53 @Override 54 protected byte getDigitPos(int position) { 55 if (position < 0 || position >= 16) return 0; 56 return (byte) ((bcd >>> (position * 4)) & 0xf); 57 } 58 59 @Override 60 protected void setDigitPos(int position, byte value) { 61 assert position >= 0 && position < 16; 62 int shift = position * 4; 63 bcd = bcd & ~(0xfL << shift) | ((long) value << shift); 64 } 65 66 @Override 67 protected void shiftLeft(int numDigits) { 68 assert precision + numDigits <= 16; 69 bcd <<= (numDigits * 4); 70 scale -= numDigits; 71 precision += numDigits; 72 } 73 74 @Override 75 protected void shiftRight(int numDigits) { 76 bcd >>>= (numDigits * 4); 77 scale += numDigits; 78 precision -= numDigits; 79 } 80 81 @Override 82 protected void setBcdToZero() { 83 bcd = 0L; 84 scale = 0; 85 precision = 0; 86 isApproximate = false; 87 origDouble = 0; 88 origDelta = 0; 89 } 90 91 @Override 92 protected void readIntToBcd(int n) { 93 assert n != 0; 94 long result = 0L; 95 int i = 16; 96 for (; n != 0; n /= 10, i--) { 97 result = (result >>> 4) + (((long) n % 10) << 60); 98 } 99 // ints can't overflow the 16 digits in the BCD, so scale is always zero 100 bcd = result >>> (i * 4); 101 scale = 0; 102 precision = 16 - i; 103 } 104 105 @Override 106 protected void readLongToBcd(long n) { 107 assert n != 0; 108 long result = 0L; 109 int i = 16; 110 for (; n != 0L; n /= 10L, i--) { 111 result = (result >>> 4) + ((n % 10) << 60); 112 } 113 int adjustment = (i > 0) ? i : 0; 114 bcd = result >>> (adjustment * 4); 115 scale = (i < 0) ? -i : 0; 116 precision = 16 - i; 117 } 118 119 @Override 120 protected void readBigIntegerToBcd(BigInteger n) { 121 assert n.signum() != 0; 122 long result = 0L; 123 int i = 16; 124 for (; n.signum() != 0; i--) { 125 BigInteger[] temp = n.divideAndRemainder(BigInteger.TEN); 126 result = (result >>> 4) + (temp[1].longValue() << 60); 127 n = temp[0]; 128 } 129 int adjustment = (i > 0) ? i : 0; 130 bcd = result >>> (adjustment * 4); 131 scale = (i < 0) ? -i : 0; 132 } 133 134 @Override 135 protected BigDecimal bcdToBigDecimal() { 136 long tempLong = 0L; 137 for (int shift = (precision - 1); shift >= 0; shift--) { 138 tempLong = tempLong * 10 + getDigitPos(shift); 139 } 140 BigDecimal result = BigDecimal.valueOf(tempLong); 141 result = result.scaleByPowerOfTen(scale); 142 if (isNegative()) result = result.negate(); 143 return result; 144 } 145 146 @Override 147 protected void compact() { 148 // Special handling for 0 149 if (bcd == 0L) { 150 scale = 0; 151 precision = 0; 152 return; 153 } 154 155 // Compact the number (remove trailing zeros) 156 int delta = Long.numberOfTrailingZeros(bcd) / 4; 157 bcd >>>= delta * 4; 158 scale += delta; 159 160 // Compute precision 161 precision = 16 - (Long.numberOfLeadingZeros(bcd) / 4); 162 } 163 164 @Override 165 protected void copyBcdFrom(DecimalQuantity _other) { 166 DecimalQuantity_64BitBCD other = (DecimalQuantity_64BitBCD) _other; 167 bcd = other.bcd; 168 } 169 170 @Override 171 public String toString() { 172 return String.format( 173 "<DecimalQuantity2 %s:%d:%d:%s %016XE%d>", 174 (lOptPos > 1000 ? "max" : String.valueOf(lOptPos)), 175 lReqPos, 176 rReqPos, 177 (rOptPos < -1000 ? "min" : String.valueOf(rOptPos)), 178 bcd, 179 scale); 180 } 181} 182