| // © 2017 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html#License |
| package com.ibm.icu.dev.impl.number; |
| |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| |
| import com.ibm.icu.impl.number.DecimalQuantity; |
| import com.ibm.icu.impl.number.DecimalQuantity_AbstractBCD; |
| |
| public final class DecimalQuantity_64BitBCD extends DecimalQuantity_AbstractBCD { |
| |
| /** |
| * The BCD of the 16 digits of the number represented by this object. Every 4 bits of the long map |
| * to one digit. For example, the number "12345" in BCD is "0x12345". |
| * |
| * <p>Whenever bcd changes internally, {@link #compact()} must be called, except in special cases |
| * like setting the digit to zero. |
| */ |
| private long bcd; |
| |
| @Override |
| public int maxRepresentableDigits() { |
| return 16; |
| } |
| |
| public DecimalQuantity_64BitBCD(long input) { |
| setToLong(input); |
| } |
| |
| public DecimalQuantity_64BitBCD(int input) { |
| setToInt(input); |
| } |
| |
| public DecimalQuantity_64BitBCD(double input) { |
| setToDouble(input); |
| } |
| |
| public DecimalQuantity_64BitBCD(BigInteger input) { |
| setToBigInteger(input); |
| } |
| |
| public DecimalQuantity_64BitBCD(BigDecimal input) { |
| setToBigDecimal(input); |
| } |
| |
| public DecimalQuantity_64BitBCD(DecimalQuantity_64BitBCD other) { |
| copyFrom(other); |
| } |
| |
| @Override |
| public DecimalQuantity createCopy() { |
| return new DecimalQuantity_64BitBCD(this); |
| } |
| |
| @Override |
| protected byte getDigitPos(int position) { |
| if (position < 0 || position >= 16) return 0; |
| return (byte) ((bcd >>> (position * 4)) & 0xf); |
| } |
| |
| @Override |
| protected void setDigitPos(int position, byte value) { |
| assert position >= 0 && position < 16; |
| int shift = position * 4; |
| bcd = bcd & ~(0xfL << shift) | ((long) value << shift); |
| } |
| |
| @Override |
| protected void shiftLeft(int numDigits) { |
| assert precision + numDigits <= 16; |
| bcd <<= (numDigits * 4); |
| scale -= numDigits; |
| precision += numDigits; |
| } |
| |
| @Override |
| protected void shiftRight(int numDigits) { |
| bcd >>>= (numDigits * 4); |
| scale += numDigits; |
| precision -= numDigits; |
| } |
| |
| @Override |
| protected void popFromLeft(int numDigits) { |
| bcd &= (1L << ((precision - numDigits) * 4)) - 1; |
| precision -= numDigits; |
| } |
| |
| @Override |
| protected void setBcdToZero() { |
| bcd = 0L; |
| scale = 0; |
| precision = 0; |
| isApproximate = false; |
| origDouble = 0; |
| origDelta = 0; |
| exponent = 0; |
| } |
| |
| @Override |
| protected void readIntToBcd(int n) { |
| assert n != 0; |
| long result = 0L; |
| int i = 16; |
| for (; n != 0; n /= 10, i--) { |
| result = (result >>> 4) + (((long) n % 10) << 60); |
| } |
| // ints can't overflow the 16 digits in the BCD, so scale is always zero |
| bcd = result >>> (i * 4); |
| scale = 0; |
| precision = 16 - i; |
| } |
| |
| @Override |
| protected void readLongToBcd(long n) { |
| assert n != 0; |
| long result = 0L; |
| int i = 16; |
| for (; n != 0L; n /= 10L, i--) { |
| result = (result >>> 4) + ((n % 10) << 60); |
| } |
| int adjustment = (i > 0) ? i : 0; |
| bcd = result >>> (adjustment * 4); |
| scale = (i < 0) ? -i : 0; |
| precision = 16 - i; |
| } |
| |
| @Override |
| protected void readBigIntegerToBcd(BigInteger n) { |
| assert n.signum() != 0; |
| long result = 0L; |
| int i = 16; |
| for (; n.signum() != 0; i--) { |
| BigInteger[] temp = n.divideAndRemainder(BigInteger.TEN); |
| result = (result >>> 4) + (temp[1].longValue() << 60); |
| n = temp[0]; |
| } |
| int adjustment = (i > 0) ? i : 0; |
| bcd = result >>> (adjustment * 4); |
| scale = (i < 0) ? -i : 0; |
| } |
| |
| @Override |
| protected BigDecimal bcdToBigDecimal() { |
| long tempLong = 0L; |
| for (int shift = (precision - 1); shift >= 0; shift--) { |
| tempLong = tempLong * 10 + getDigitPos(shift); |
| } |
| BigDecimal result = BigDecimal.valueOf(tempLong); |
| result = result.scaleByPowerOfTen(scale); |
| if (isNegative()) result = result.negate(); |
| return result; |
| } |
| |
| @Override |
| protected void compact() { |
| // Special handling for 0 |
| if (bcd == 0L) { |
| scale = 0; |
| precision = 0; |
| return; |
| } |
| |
| // Compact the number (remove trailing zeros) |
| int delta = Long.numberOfTrailingZeros(bcd) / 4; |
| bcd >>>= delta * 4; |
| scale += delta; |
| |
| // Compute precision |
| precision = 16 - (Long.numberOfLeadingZeros(bcd) / 4); |
| } |
| |
| @Override |
| protected void copyBcdFrom(DecimalQuantity _other) { |
| DecimalQuantity_64BitBCD other = (DecimalQuantity_64BitBCD) _other; |
| bcd = other.bcd; |
| } |
| |
| @Override |
| public String toString() { |
| return String.format( |
| "<DecimalQuantity2 %d:%d %016XE%d>", |
| lReqPos, |
| rReqPos, |
| bcd, |
| scale); |
| } |
| } |