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