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