LEFT | RIGHT |
1 // © 2017 and later: Unicode, Inc. and others. | 1 // © 2017 and later: Unicode, Inc. and others. |
2 // License & terms of use: http://www.unicode.org/copyright.html#License | 2 // License & terms of use: http://www.unicode.org/copyright.html#License |
3 package com.ibm.icu.impl.number; | 3 package com.ibm.icu.impl.number; |
4 | 4 |
5 import java.math.BigDecimal; | 5 import java.math.BigDecimal; |
6 import java.math.BigInteger; | 6 import java.math.BigInteger; |
7 | 7 |
8 /** | 8 /** |
9 * A DecimalQuantity with internal storage as a 64-bit BCD, with fallback to a b
yte array | 9 * A DecimalQuantity with internal storage as a 64-bit BCD, with fallback to a b
yte array for numbers |
10 * for numbers that don't fit into the standard BCD. | 10 * that don't fit into the standard BCD. |
11 */ | 11 */ |
12 public final class DecimalQuantity_DualStorageBCD extends DecimalQuantity_Abstra
ctBCD { | 12 public final class DecimalQuantity_DualStorageBCD extends DecimalQuantity_Abstra
ctBCD { |
13 | 13 |
14 /** | 14 /** |
15 * The BCD of the 16 digits of the number represented by this object. Every 4
bits of the long map | 15 * The BCD of the 16 digits of the number represented by this object. Every
4 bits of the long map to |
16 * to one digit. For example, the number "12345" in BCD is "0x12345". | 16 * one digit. For example, the number "12345" in BCD is "0x12345". |
17 * | 17 * |
18 * <p>Whenever bcd changes internally, {@link #compact()} must be called, exce
pt in special cases | 18 * <p> |
19 * like setting the digit to zero. | 19 * Whenever bcd changes internally, {@link #compact()} must be called, excep
t in special cases like |
20 */ | 20 * setting the digit to zero. |
21 private byte[] bcdBytes; | 21 */ |
22 | 22 private byte[] bcdBytes; |
23 private long bcdLong = 0L; | 23 |
24 | 24 private long bcdLong = 0L; |
25 private boolean usingBytes = false; | 25 |
26 | 26 private boolean usingBytes = false; |
27 @Override | 27 |
28 public int maxRepresentableDigits() { | 28 @Override |
29 return Integer.MAX_VALUE; | 29 public int maxRepresentableDigits() { |
30 } | 30 return Integer.MAX_VALUE; |
31 | 31 } |
32 public DecimalQuantity_DualStorageBCD() { | 32 |
33 setBcdToZero(); | 33 public DecimalQuantity_DualStorageBCD() { |
34 flags = 0; | |
35 } | |
36 | |
37 public DecimalQuantity_DualStorageBCD(long input) { | |
38 setToLong(input); | |
39 } | |
40 | |
41 public DecimalQuantity_DualStorageBCD(int input) { | |
42 setToInt(input); | |
43 } | |
44 | |
45 public DecimalQuantity_DualStorageBCD(double input) { | |
46 setToDouble(input); | |
47 } | |
48 | |
49 public DecimalQuantity_DualStorageBCD(BigInteger input) { | |
50 setToBigInteger(input); | |
51 } | |
52 | |
53 public DecimalQuantity_DualStorageBCD(BigDecimal input) { | |
54 setToBigDecimal(input); | |
55 } | |
56 | |
57 public DecimalQuantity_DualStorageBCD(DecimalQuantity_DualStorageBCD other) { | |
58 copyFrom(other); | |
59 } | |
60 | |
61 public DecimalQuantity_DualStorageBCD(Number number) { | |
62 if (number instanceof Long) { | |
63 setToLong(number.longValue()); | |
64 } else if (number instanceof Integer) { | |
65 setToInt(number.intValue()); | |
66 } else if (number instanceof Float) { | |
67 setToDouble(number.doubleValue()); | |
68 } else if (number instanceof Double) { | |
69 setToDouble(number.doubleValue()); | |
70 } else if (number instanceof BigInteger) { | |
71 setToBigInteger((BigInteger) number); | |
72 } else if (number instanceof BigDecimal) { | |
73 setToBigDecimal((BigDecimal) number); | |
74 } else if (number instanceof com.ibm.icu.math.BigDecimal) { | |
75 setToBigDecimal(((com.ibm.icu.math.BigDecimal) number).toBigDecimal()); | |
76 } else { | |
77 throw new IllegalArgumentException( | |
78 "Number is of an unsupported type: " + number.getClass().getName()); | |
79 } | |
80 } | |
81 | |
82 @Override | |
83 public DecimalQuantity createCopy() { | |
84 return new DecimalQuantity_DualStorageBCD(this); | |
85 } | |
86 | |
87 @Override | |
88 protected byte getDigitPos(int position) { | |
89 if (usingBytes) { | |
90 if (position < 0 || position > precision) return 0; | |
91 return bcdBytes[position]; | |
92 } else { | |
93 if (position < 0 || position >= 16) return 0; | |
94 return (byte) ((bcdLong >>> (position * 4)) & 0xf); | |
95 } | |
96 } | |
97 | |
98 @Override | |
99 protected void setDigitPos(int position, byte value) { | |
100 assert position >= 0; | |
101 if (usingBytes) { | |
102 ensureCapacity(position + 1); | |
103 bcdBytes[position] = value; | |
104 } else if (position >= 16) { | |
105 switchStorage(); | |
106 ensureCapacity(position + 1); | |
107 bcdBytes[position] = value; | |
108 } else { | |
109 int shift = position * 4; | |
110 bcdLong = bcdLong & ~(0xfL << shift) | ((long) value << shift); | |
111 } | |
112 } | |
113 | |
114 @Override | |
115 protected void shiftLeft(int numDigits) { | |
116 if (!usingBytes && precision + numDigits > 16) { | |
117 switchStorage(); | |
118 } | |
119 if (usingBytes) { | |
120 ensureCapacity(precision + numDigits); | |
121 int i = precision + numDigits - 1; | |
122 for (; i >= numDigits; i--) { | |
123 bcdBytes[i] = bcdBytes[i - numDigits]; | |
124 } | |
125 for (; i >= 0; i--) { | |
126 bcdBytes[i] = 0; | |
127 } | |
128 } else { | |
129 bcdLong <<= (numDigits * 4); | |
130 } | |
131 scale -= numDigits; | |
132 precision += numDigits; | |
133 } | |
134 | |
135 @Override | |
136 protected void shiftRight(int numDigits) { | |
137 if (usingBytes) { | |
138 int i = 0; | |
139 for (; i < precision - numDigits; i++) { | |
140 bcdBytes[i] = bcdBytes[i + numDigits]; | |
141 } | |
142 for (; i < precision; i++) { | |
143 bcdBytes[i] = 0; | |
144 } | |
145 } else { | |
146 bcdLong >>>= (numDigits * 4); | |
147 } | |
148 scale += numDigits; | |
149 precision -= numDigits; | |
150 } | |
151 | |
152 @Override | |
153 protected void setBcdToZero() { | |
154 if (usingBytes) { | |
155 bcdBytes = null; | |
156 usingBytes = false; | |
157 } | |
158 bcdLong = 0L; | |
159 scale = 0; | |
160 precision = 0; | |
161 isApproximate = false; | |
162 origDouble = 0; | |
163 origDelta = 0; | |
164 } | |
165 | |
166 @Override | |
167 protected void readIntToBcd(int n) { | |
168 assert n != 0; | |
169 // ints always fit inside the long implementation. | |
170 long result = 0L; | |
171 int i = 16; | |
172 for (; n != 0; n /= 10, i--) { | |
173 result = (result >>> 4) + (((long) n % 10) << 60); | |
174 } | |
175 assert !usingBytes; | |
176 bcdLong = result >>> (i * 4); | |
177 scale = 0; | |
178 precision = 16 - i; | |
179 } | |
180 | |
181 @Override | |
182 protected void readLongToBcd(long n) { | |
183 assert n != 0; | |
184 if (n >= 10000000000000000L) { | |
185 ensureCapacity(); | |
186 int i = 0; | |
187 for (; n != 0L; n /= 10L, i++) { | |
188 bcdBytes[i] = (byte) (n % 10); | |
189 } | |
190 assert usingBytes; | |
191 scale = 0; | |
192 precision = i; | |
193 } else { | |
194 long result = 0L; | |
195 int i = 16; | |
196 for (; n != 0L; n /= 10L, i--) { | |
197 result = (result >>> 4) + ((n % 10) << 60); | |
198 } | |
199 assert i >= 0; | |
200 assert !usingBytes; | |
201 bcdLong = result >>> (i * 4); | |
202 scale = 0; | |
203 precision = 16 - i; | |
204 } | |
205 } | |
206 | |
207 @Override | |
208 protected void readBigIntegerToBcd(BigInteger n) { | |
209 assert n.signum() != 0; | |
210 ensureCapacity(); // allocate initial byte array | |
211 int i = 0; | |
212 for (; n.signum() != 0; i++) { | |
213 BigInteger[] temp = n.divideAndRemainder(BigInteger.TEN); | |
214 ensureCapacity(i + 1); | |
215 bcdBytes[i] = temp[1].byteValue(); | |
216 n = temp[0]; | |
217 } | |
218 scale = 0; | |
219 precision = i; | |
220 } | |
221 | |
222 @Override | |
223 protected BigDecimal bcdToBigDecimal() { | |
224 if (usingBytes) { | |
225 // Converting to a string here is faster than doing BigInteger/BigDecimal
arithmetic. | |
226 BigDecimal result = new BigDecimal(toNumberString()); | |
227 if (isNegative()) { | |
228 result = result.negate(); | |
229 } | |
230 return result; | |
231 } else { | |
232 long tempLong = 0L; | |
233 for (int shift = (precision - 1); shift >= 0; shift--) { | |
234 tempLong = tempLong * 10 + getDigitPos(shift); | |
235 } | |
236 BigDecimal result = BigDecimal.valueOf(tempLong); | |
237 result = result.scaleByPowerOfTen(scale); | |
238 if (isNegative()) result = result.negate(); | |
239 return result; | |
240 } | |
241 } | |
242 | |
243 @Override | |
244 protected void compact() { | |
245 if (usingBytes) { | |
246 int delta = 0; | |
247 for (; delta < precision && bcdBytes[delta] == 0; delta++) ; | |
248 if (delta == precision) { | |
249 // Number is zero | |
250 setBcdToZero(); | 34 setBcdToZero(); |
251 return; | 35 flags = 0; |
252 } else { | 36 } |
253 // Remove trailing zeros | 37 |
254 shiftRight(delta); | 38 public DecimalQuantity_DualStorageBCD(long input) { |
255 } | 39 setToLong(input); |
256 | 40 } |
257 // Compute precision | 41 |
258 int leading = precision - 1; | 42 public DecimalQuantity_DualStorageBCD(int input) { |
259 for (; leading >= 0 && bcdBytes[leading] == 0; leading--) ; | 43 setToInt(input); |
260 precision = leading + 1; | 44 } |
261 | 45 |
262 // Switch storage mechanism if possible | 46 public DecimalQuantity_DualStorageBCD(double input) { |
263 if (precision <= 16) { | 47 setToDouble(input); |
264 switchStorage(); | 48 } |
265 } | 49 |
266 | 50 public DecimalQuantity_DualStorageBCD(BigInteger input) { |
267 } else { | 51 setToBigInteger(input); |
268 if (bcdLong == 0L) { | 52 } |
269 // Number is zero | 53 |
| 54 public DecimalQuantity_DualStorageBCD(BigDecimal input) { |
| 55 setToBigDecimal(input); |
| 56 } |
| 57 |
| 58 public DecimalQuantity_DualStorageBCD(DecimalQuantity_DualStorageBCD other)
{ |
| 59 copyFrom(other); |
| 60 } |
| 61 |
| 62 public DecimalQuantity_DualStorageBCD(Number number) { |
| 63 if (number instanceof Long) { |
| 64 setToLong(number.longValue()); |
| 65 } else if (number instanceof Integer) { |
| 66 setToInt(number.intValue()); |
| 67 } else if (number instanceof Float) { |
| 68 setToDouble(number.doubleValue()); |
| 69 } else if (number instanceof Double) { |
| 70 setToDouble(number.doubleValue()); |
| 71 } else if (number instanceof BigInteger) { |
| 72 setToBigInteger((BigInteger) number); |
| 73 } else if (number instanceof BigDecimal) { |
| 74 setToBigDecimal((BigDecimal) number); |
| 75 } else if (number instanceof com.ibm.icu.math.BigDecimal) { |
| 76 setToBigDecimal(((com.ibm.icu.math.BigDecimal) number).toBigDecimal(
)); |
| 77 } else { |
| 78 throw new IllegalArgumentException( |
| 79 "Number is of an unsupported type: " + number.getClass().get
Name()); |
| 80 } |
| 81 } |
| 82 |
| 83 @Override |
| 84 public DecimalQuantity createCopy() { |
| 85 return new DecimalQuantity_DualStorageBCD(this); |
| 86 } |
| 87 |
| 88 @Override |
| 89 protected byte getDigitPos(int position) { |
| 90 if (usingBytes) { |
| 91 if (position < 0 || position > precision) |
| 92 return 0; |
| 93 return bcdBytes[position]; |
| 94 } else { |
| 95 if (position < 0 || position >= 16) |
| 96 return 0; |
| 97 return (byte) ((bcdLong >>> (position * 4)) & 0xf); |
| 98 } |
| 99 } |
| 100 |
| 101 @Override |
| 102 protected void setDigitPos(int position, byte value) { |
| 103 assert position >= 0; |
| 104 if (usingBytes) { |
| 105 ensureCapacity(position + 1); |
| 106 bcdBytes[position] = value; |
| 107 } else if (position >= 16) { |
| 108 switchStorage(); |
| 109 ensureCapacity(position + 1); |
| 110 bcdBytes[position] = value; |
| 111 } else { |
| 112 int shift = position * 4; |
| 113 bcdLong = bcdLong & ~(0xfL << shift) | ((long) value << shift); |
| 114 } |
| 115 } |
| 116 |
| 117 @Override |
| 118 protected void shiftLeft(int numDigits) { |
| 119 if (!usingBytes && precision + numDigits > 16) { |
| 120 switchStorage(); |
| 121 } |
| 122 if (usingBytes) { |
| 123 ensureCapacity(precision + numDigits); |
| 124 int i = precision + numDigits - 1; |
| 125 for (; i >= numDigits; i--) { |
| 126 bcdBytes[i] = bcdBytes[i - numDigits]; |
| 127 } |
| 128 for (; i >= 0; i--) { |
| 129 bcdBytes[i] = 0; |
| 130 } |
| 131 } else { |
| 132 bcdLong <<= (numDigits * 4); |
| 133 } |
| 134 scale -= numDigits; |
| 135 precision += numDigits; |
| 136 } |
| 137 |
| 138 @Override |
| 139 protected void shiftRight(int numDigits) { |
| 140 if (usingBytes) { |
| 141 int i = 0; |
| 142 for (; i < precision - numDigits; i++) { |
| 143 bcdBytes[i] = bcdBytes[i + numDigits]; |
| 144 } |
| 145 for (; i < precision; i++) { |
| 146 bcdBytes[i] = 0; |
| 147 } |
| 148 } else { |
| 149 bcdLong >>>= (numDigits * 4); |
| 150 } |
| 151 scale += numDigits; |
| 152 precision -= numDigits; |
| 153 } |
| 154 |
| 155 @Override |
| 156 protected void setBcdToZero() { |
| 157 if (usingBytes) { |
| 158 bcdBytes = null; |
| 159 usingBytes = false; |
| 160 } |
| 161 bcdLong = 0L; |
| 162 scale = 0; |
| 163 precision = 0; |
| 164 isApproximate = false; |
| 165 origDouble = 0; |
| 166 origDelta = 0; |
| 167 } |
| 168 |
| 169 @Override |
| 170 protected void readIntToBcd(int n) { |
| 171 assert n != 0; |
| 172 // ints always fit inside the long implementation. |
| 173 long result = 0L; |
| 174 int i = 16; |
| 175 for (; n != 0; n /= 10, i--) { |
| 176 result = (result >>> 4) + (((long) n % 10) << 60); |
| 177 } |
| 178 assert !usingBytes; |
| 179 bcdLong = result >>> (i * 4); |
| 180 scale = 0; |
| 181 precision = 16 - i; |
| 182 } |
| 183 |
| 184 @Override |
| 185 protected void readLongToBcd(long n) { |
| 186 assert n != 0; |
| 187 if (n >= 10000000000000000L) { |
| 188 ensureCapacity(); |
| 189 int i = 0; |
| 190 for (; n != 0L; n /= 10L, i++) { |
| 191 bcdBytes[i] = (byte) (n % 10); |
| 192 } |
| 193 assert usingBytes; |
| 194 scale = 0; |
| 195 precision = i; |
| 196 } else { |
| 197 long result = 0L; |
| 198 int i = 16; |
| 199 for (; n != 0L; n /= 10L, i--) { |
| 200 result = (result >>> 4) + ((n % 10) << 60); |
| 201 } |
| 202 assert i >= 0; |
| 203 assert !usingBytes; |
| 204 bcdLong = result >>> (i * 4); |
| 205 scale = 0; |
| 206 precision = 16 - i; |
| 207 } |
| 208 } |
| 209 |
| 210 @Override |
| 211 protected void readBigIntegerToBcd(BigInteger n) { |
| 212 assert n.signum() != 0; |
| 213 ensureCapacity(); // allocate initial byte array |
| 214 int i = 0; |
| 215 for (; n.signum() != 0; i++) { |
| 216 BigInteger[] temp = n.divideAndRemainder(BigInteger.TEN); |
| 217 ensureCapacity(i + 1); |
| 218 bcdBytes[i] = temp[1].byteValue(); |
| 219 n = temp[0]; |
| 220 } |
| 221 scale = 0; |
| 222 precision = i; |
| 223 } |
| 224 |
| 225 @Override |
| 226 protected BigDecimal bcdToBigDecimal() { |
| 227 if (usingBytes) { |
| 228 // Converting to a string here is faster than doing BigInteger/BigDe
cimal arithmetic. |
| 229 BigDecimal result = new BigDecimal(toNumberString()); |
| 230 if (isNegative()) { |
| 231 result = result.negate(); |
| 232 } |
| 233 return result; |
| 234 } else { |
| 235 long tempLong = 0L; |
| 236 for (int shift = (precision - 1); shift >= 0; shift--) { |
| 237 tempLong = tempLong * 10 + getDigitPos(shift); |
| 238 } |
| 239 BigDecimal result = BigDecimal.valueOf(tempLong); |
| 240 result = result.scaleByPowerOfTen(scale); |
| 241 if (isNegative()) |
| 242 result = result.negate(); |
| 243 return result; |
| 244 } |
| 245 } |
| 246 |
| 247 @Override |
| 248 protected void compact() { |
| 249 if (usingBytes) { |
| 250 int delta = 0; |
| 251 for (; delta < precision && bcdBytes[delta] == 0; delta++) |
| 252 ; |
| 253 if (delta == precision) { |
| 254 // Number is zero |
| 255 setBcdToZero(); |
| 256 return; |
| 257 } else { |
| 258 // Remove trailing zeros |
| 259 shiftRight(delta); |
| 260 } |
| 261 |
| 262 // Compute precision |
| 263 int leading = precision - 1; |
| 264 for (; leading >= 0 && bcdBytes[leading] == 0; leading--) |
| 265 ; |
| 266 precision = leading + 1; |
| 267 |
| 268 // Switch storage mechanism if possible |
| 269 if (precision <= 16) { |
| 270 switchStorage(); |
| 271 } |
| 272 |
| 273 } else { |
| 274 if (bcdLong == 0L) { |
| 275 // Number is zero |
| 276 setBcdToZero(); |
| 277 return; |
| 278 } |
| 279 |
| 280 // Compact the number (remove trailing zeros) |
| 281 int delta = Long.numberOfTrailingZeros(bcdLong) / 4; |
| 282 bcdLong >>>= delta * 4; |
| 283 scale += delta; |
| 284 |
| 285 // Compute precision |
| 286 precision = 16 - (Long.numberOfLeadingZeros(bcdLong) / 4); |
| 287 } |
| 288 } |
| 289 |
| 290 /** Ensure that a byte array of at least 40 digits is allocated. */ |
| 291 private void ensureCapacity() { |
| 292 ensureCapacity(40); |
| 293 } |
| 294 |
| 295 private void ensureCapacity(int capacity) { |
| 296 if (capacity == 0) |
| 297 return; |
| 298 int oldCapacity = usingBytes ? bcdBytes.length : 0; |
| 299 if (!usingBytes) { |
| 300 bcdBytes = new byte[capacity]; |
| 301 } else if (oldCapacity < capacity) { |
| 302 byte[] bcd1 = new byte[capacity * 2]; |
| 303 System.arraycopy(bcdBytes, 0, bcd1, 0, oldCapacity); |
| 304 bcdBytes = bcd1; |
| 305 } |
| 306 usingBytes = true; |
| 307 } |
| 308 |
| 309 /** Switches the internal storage mechanism between the 64-bit long and the
byte array. */ |
| 310 private void switchStorage() { |
| 311 if (usingBytes) { |
| 312 // Change from bytes to long |
| 313 bcdLong = 0L; |
| 314 for (int i = precision - 1; i >= 0; i--) { |
| 315 bcdLong <<= 4; |
| 316 bcdLong |= bcdBytes[i]; |
| 317 } |
| 318 bcdBytes = null; |
| 319 usingBytes = false; |
| 320 } else { |
| 321 // Change from long to bytes |
| 322 ensureCapacity(); |
| 323 for (int i = 0; i < precision; i++) { |
| 324 bcdBytes[i] = (byte) (bcdLong & 0xf); |
| 325 bcdLong >>>= 4; |
| 326 } |
| 327 assert usingBytes; |
| 328 } |
| 329 } |
| 330 |
| 331 @Override |
| 332 protected void copyBcdFrom(DecimalQuantity _other) { |
| 333 DecimalQuantity_DualStorageBCD other = (DecimalQuantity_DualStorageBCD)
_other; |
270 setBcdToZero(); | 334 setBcdToZero(); |
271 return; | 335 if (other.usingBytes) { |
272 } | 336 ensureCapacity(other.precision); |
273 | 337 System.arraycopy(other.bcdBytes, 0, bcdBytes, 0, other.precision); |
274 // Compact the number (remove trailing zeros) | 338 } else { |
275 int delta = Long.numberOfTrailingZeros(bcdLong) / 4; | 339 bcdLong = other.bcdLong; |
276 bcdLong >>>= delta * 4; | 340 } |
277 scale += delta; | 341 } |
278 | 342 |
279 // Compute precision | 343 /** |
280 precision = 16 - (Long.numberOfLeadingZeros(bcdLong) / 4); | 344 * Checks whether the bytes stored in this instance are all valid. For inter
nal unit testing only. |
281 } | 345 * |
282 } | 346 * @return An error message if this instance is invalid, or null if this ins
tance is healthy. |
283 | 347 * @internal |
284 /** Ensure that a byte array of at least 40 digits is allocated. */ | 348 * @deprecated This API is for ICU internal use only. |
285 private void ensureCapacity() { | 349 */ |
286 ensureCapacity(40); | 350 @Deprecated |
287 } | 351 public String checkHealth() { |
288 | 352 if (usingBytes) { |
289 private void ensureCapacity(int capacity) { | 353 if (bcdLong != 0) |
290 if (capacity == 0) return; | 354 return "Value in bcdLong but we are in byte mode"; |
291 int oldCapacity = usingBytes ? bcdBytes.length : 0; | 355 if (precision == 0) |
292 if (!usingBytes) { | 356 return "Zero precision but we are in byte mode"; |
293 bcdBytes = new byte[capacity]; | 357 if (precision > bcdBytes.length) |
294 } else if (oldCapacity < capacity) { | 358 return "Precision exceeds length of byte array"; |
295 byte[] bcd1 = new byte[capacity * 2]; | 359 if (getDigitPos(precision - 1) == 0) |
296 System.arraycopy(bcdBytes, 0, bcd1, 0, oldCapacity); | 360 return "Most significant digit is zero in byte mode"; |
297 bcdBytes = bcd1; | 361 if (getDigitPos(0) == 0) |
298 } | 362 return "Least significant digit is zero in long mode"; |
299 usingBytes = true; | 363 for (int i = 0; i < precision; i++) { |
300 } | 364 if (getDigitPos(i) >= 10) |
301 | 365 return "Digit exceeding 10 in byte array"; |
302 /** Switches the internal storage mechanism between the 64-bit long and the by
te array. */ | 366 if (getDigitPos(i) < 0) |
303 private void switchStorage() { | 367 return "Digit below 0 in byte array"; |
304 if (usingBytes) { | 368 } |
305 // Change from bytes to long | 369 for (int i = precision; i < bcdBytes.length; i++) { |
306 bcdLong = 0L; | 370 if (getDigitPos(i) != 0) |
307 for (int i = precision - 1; i >= 0; i--) { | 371 return "Nonzero digits outside of range in byte array"; |
308 bcdLong <<= 4; | 372 } |
309 bcdLong |= bcdBytes[i]; | 373 } else { |
310 } | 374 if (bcdBytes != null) { |
311 bcdBytes = null; | 375 for (int i = 0; i < bcdBytes.length; i++) { |
312 usingBytes = false; | 376 if (bcdBytes[i] != 0) |
313 } else { | 377 return "Nonzero digits in byte array but we are in long
mode"; |
314 // Change from long to bytes | 378 } |
315 ensureCapacity(); | 379 } |
316 for (int i = 0; i < precision; i++) { | 380 if (precision == 0 && bcdLong != 0) |
317 bcdBytes[i] = (byte) (bcdLong & 0xf); | 381 return "Value in bcdLong even though precision is zero"; |
318 bcdLong >>>= 4; | 382 if (precision > 16) |
319 } | 383 return "Precision exceeds length of long"; |
320 assert usingBytes; | 384 if (precision != 0 && getDigitPos(precision - 1) == 0) |
321 } | 385 return "Most significant digit is zero in long mode"; |
322 } | 386 if (precision != 0 && getDigitPos(0) == 0) |
323 | 387 return "Least significant digit is zero in long mode"; |
324 @Override | 388 for (int i = 0; i < precision; i++) { |
325 protected void copyBcdFrom(DecimalQuantity _other) { | 389 if (getDigitPos(i) >= 10) |
326 DecimalQuantity_DualStorageBCD other = (DecimalQuantity_DualStorageBCD) _oth
er; | 390 return "Digit exceeding 10 in long"; |
327 setBcdToZero(); | 391 if (getDigitPos(i) < 0) |
328 if (other.usingBytes) { | 392 return "Digit below 0 in long (?!)"; |
329 ensureCapacity(other.precision); | 393 } |
330 System.arraycopy(other.bcdBytes, 0, bcdBytes, 0, other.precision); | 394 for (int i = precision; i < 16; i++) { |
331 } else { | 395 if (getDigitPos(i) != 0) |
332 bcdLong = other.bcdLong; | 396 return "Nonzero digits outside of range in long"; |
333 } | 397 } |
334 } | 398 } |
335 | 399 |
336 /** | 400 return null; |
337 * Checks whether the bytes stored in this instance are all valid. For interna
l unit testing only. | 401 } |
338 * | 402 |
339 * @return An error message if this instance is invalid, or null if this insta
nce is healthy. | 403 /** |
340 * @internal | 404 * Checks whether this {@link DecimalQuantity_DualStorageBCD} is using its i
nternal byte array |
341 * @deprecated This API is for ICU internal use only. | 405 * storage mechanism. |
342 */ | 406 * |
343 @Deprecated | 407 * @return true if an internal byte array is being used; false if a long is
being used. |
344 public String checkHealth() { | 408 * @internal |
345 if (usingBytes) { | 409 * @deprecated This API is ICU internal only. |
346 if (bcdLong != 0) return "Value in bcdLong but we are in byte mode"; | 410 */ |
347 if (precision == 0) return "Zero precision but we are in byte mode"; | 411 @Deprecated |
348 if (precision > bcdBytes.length) return "Precision exceeds length of byte
array"; | 412 public boolean isUsingBytes() { |
349 if (getDigitPos(precision - 1) == 0) return "Most significant digit is zer
o in byte mode"; | 413 return usingBytes; |
350 if (getDigitPos(0) == 0) return "Least significant digit is zero in long m
ode"; | 414 } |
351 for (int i = 0; i < precision; i++) { | 415 |
352 if (getDigitPos(i) >= 10) return "Digit exceeding 10 in byte array"; | 416 @Override |
353 if (getDigitPos(i) < 0) return "Digit below 0 in byte array"; | 417 public String toString() { |
354 } | 418 return String.format("<DecimalQuantity %s:%d:%d:%s %s %s>", |
355 for (int i = precision; i < bcdBytes.length; i++) { | 419 (lOptPos > 1000 ? "999" : String.valueOf(lOptPos)), |
356 if (getDigitPos(i) != 0) return "Nonzero digits outside of range in byte
array"; | 420 lReqPos, |
357 } | 421 rReqPos, |
358 } else { | 422 (rOptPos < -1000 ? "-999" : String.valueOf(rOptPos)), |
359 if (bcdBytes != null) { | 423 (usingBytes ? "bytes" : "long"), |
360 for (int i = 0; i < bcdBytes.length; i++) { | 424 toNumberString()); |
361 if (bcdBytes[i] != 0) return "Nonzero digits in byte array but we are
in long mode"; | 425 } |
362 } | 426 |
363 } | 427 public String toNumberString() { |
364 if (precision == 0 && bcdLong != 0) return "Value in bcdLong even though p
recision is zero"; | 428 StringBuilder sb = new StringBuilder(); |
365 if (precision > 16) return "Precision exceeds length of long"; | 429 if (usingBytes) { |
366 if (precision != 0 && getDigitPos(precision - 1) == 0) | 430 for (int i = precision - 1; i >= 0; i--) { |
367 return "Most significant digit is zero in long mode"; | 431 sb.append(bcdBytes[i]); |
368 if (precision != 0 && getDigitPos(0) == 0) | 432 } |
369 return "Least significant digit is zero in long mode"; | 433 } else { |
370 for (int i = 0; i < precision; i++) { | 434 sb.append(Long.toHexString(bcdLong)); |
371 if (getDigitPos(i) >= 10) return "Digit exceeding 10 in long"; | 435 } |
372 if (getDigitPos(i) < 0) return "Digit below 0 in long (?!)"; | 436 sb.append("E"); |
373 } | 437 sb.append(scale); |
374 for (int i = precision; i < 16; i++) { | 438 return sb.toString(); |
375 if (getDigitPos(i) != 0) return "Nonzero digits outside of range in long
"; | 439 } |
376 } | |
377 } | |
378 | |
379 return null; | |
380 } | |
381 | |
382 /** | |
383 * Checks whether this {@link DecimalQuantity_DualStorageBCD} is using its int
ernal byte array storage mechanism. | |
384 * | |
385 * @return true if an internal byte array is being used; false if a long is be
ing used. | |
386 * @internal | |
387 * @deprecated This API is ICU internal only. | |
388 */ | |
389 @Deprecated | |
390 public boolean isUsingBytes() { | |
391 return usingBytes; | |
392 } | |
393 | |
394 @Override | |
395 public String toString() { | |
396 return String.format( | |
397 "<DecimalQuantity %s:%d:%d:%s %s %s>", | |
398 (lOptPos > 1000 ? "999" : String.valueOf(lOptPos)), | |
399 lReqPos, | |
400 rReqPos, | |
401 (rOptPos < -1000 ? "-999" : String.valueOf(rOptPos)), | |
402 (usingBytes ? "bytes" : "long"), | |
403 toNumberString()); | |
404 } | |
405 | |
406 public String toNumberString() { | |
407 StringBuilder sb = new StringBuilder(); | |
408 if (usingBytes) { | |
409 for (int i = precision - 1; i >= 0; i--) { | |
410 sb.append(bcdBytes[i]); | |
411 } | |
412 } else { | |
413 sb.append(Long.toHexString(bcdLong)); | |
414 } | |
415 sb.append("E"); | |
416 sb.append(scale); | |
417 return sb.toString(); | |
418 } | |
419 } | 440 } |
LEFT | RIGHT |