Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/jcl/src/openj9.dataaccess/share/classes/com/ibm/dataaccess/PackedDecimal.java
12575 views
1
/*[INCLUDE-IF DAA]*/
2
/*******************************************************************************
3
* Copyright (c) 2013, 2021 IBM Corp. and others
4
*
5
* This program and the accompanying materials are made available under
6
* the terms of the Eclipse Public License 2.0 which accompanies this
7
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
8
* or the Apache License, Version 2.0 which accompanies this distribution and
9
* is available at https://www.apache.org/licenses/LICENSE-2.0.
10
*
11
* This Source Code may also be made available under the following
12
* Secondary Licenses when the conditions for such availability set
13
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
14
* General Public License, version 2 with the GNU Classpath
15
* Exception [1] and GNU General Public License, version 2 with the
16
* OpenJDK Assembly Exception [2].
17
*
18
* [1] https://www.gnu.org/software/classpath/license.html
19
* [2] http://openjdk.java.net/legal/assembly-exception.html
20
*
21
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
22
*******************************************************************************/
23
package com.ibm.dataaccess;
24
25
import java.math.BigInteger;
26
import java.util.Arrays;
27
28
import com.ibm.dataaccess.CommonData;
29
30
/**
31
* Arithmetic, copying and shifting operations for Packed Decimal data.
32
*
33
* @author IBM
34
* @version $Revision$ on $Date$
35
*/
36
public final class PackedDecimal {
37
38
/**
39
* Private constructor, class contains only static methods.
40
*/
41
private PackedDecimal() {
42
super();
43
}
44
45
private static final ThreadLocal<PackedDecimalOperand> op1_threadLocal = new ThreadLocal<PackedDecimalOperand>() {
46
protected PackedDecimalOperand initialValue()
47
{
48
return new PackedDecimalOperand();
49
}
50
};
51
private static final ThreadLocal<PackedDecimalOperand> op2_threadLocal = new ThreadLocal<PackedDecimalOperand>() {
52
protected PackedDecimalOperand initialValue()
53
{
54
return new PackedDecimalOperand();
55
}
56
};
57
private static final ThreadLocal<PackedDecimalOperand> sum_threadLocal = new ThreadLocal<PackedDecimalOperand>() {
58
protected PackedDecimalOperand initialValue()
59
{
60
return new PackedDecimalOperand();
61
}
62
};
63
64
/**
65
* Checks the validity of a Packed Decimal, return code indicating the status of the Packed Decimal.
66
*
67
* @param byteArray
68
* the source container array
69
* @param offset
70
* starting offset of the Packed Decimal
71
* @param precision
72
* precision of the Packed Decimal. Maximum valid precision is 253
73
* @param ignoreHighNibbleForEvenPrecision
74
* if true, ignore to check if the top nibble (first 4 bits) of the input is an invalid sign value in the
75
* case of even precision
76
* @param canOverwriteHighNibbleForEvenPrecision
77
* if true, change the high nibble to a zero in case of even precision
78
* @return the condition code: 0 All digit codes and the sign valid 1 Sign invalid 2 At least one digit code invalid
79
* 3 Sign invalid and at least one digit code invalid
80
*
81
* @throws NullPointerException
82
* if <code>byteArray</code> is null
83
* @throws ArrayIndexOutOfBoundsException
84
* if an invalid array access occurs
85
*/
86
public static int checkPackedDecimal(byte[] byteArray, int offset,
87
int precision, boolean ignoreHighNibbleForEvenPrecision,
88
boolean canOverwriteHighNibbleForEvenPrecision) {
89
if ((offset + ((precision / 2) + 1) > byteArray.length) || (offset < 0))
90
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
91
"checkPackedDecimal is trying to access byteArray[" + offset + "] to byteArray[" + (offset + (precision / 2)) + "]" +
92
" but valid indices are from 0 to " + (byteArray.length - 1) + ".");
93
94
return checkPackedDecimal_(byteArray, offset, precision,
95
ignoreHighNibbleForEvenPrecision, canOverwriteHighNibbleForEvenPrecision);
96
}
97
98
private static int checkPackedDecimal_(byte[] byteArray, int offset,
99
int precision, boolean ignoreHighNibbleForEvenPrecision,
100
boolean canOverwriteHighNibbleForEvenPrecision) {
101
102
if (precision < 1)
103
throw new IllegalArgumentException("Illegal Precision.");
104
105
boolean evenPrecision = precision % 2 == 0 ? true : false;
106
int signOffset = offset + CommonData.getPackedByteCount(precision) - 1;
107
108
int returnCode = 0;
109
110
if (canOverwriteHighNibbleForEvenPrecision && evenPrecision) {
111
byteArray[offset] = (byte) (byteArray[offset] & CommonData.LOWER_NIBBLE_MASK);
112
}
113
114
if (evenPrecision && ignoreHighNibbleForEvenPrecision)
115
{
116
if ((byteArray[offset] & CommonData.LOWER_NIBBLE_MASK) > 0x09)
117
returnCode = 2;
118
offset++;
119
}
120
121
122
// ordinary checking places here:
123
int i;
124
for (i = offset; i < signOffset && byteArray[i] == CommonData.PACKED_ZERO; i++)
125
;
126
127
for (; i < signOffset; i++)
128
{
129
if ((byteArray[i] & CommonData.LOWER_NIBBLE_MASK) > 0x09 ||
130
(byteArray[i] & CommonData.HIGHER_NIBBLE_MASK & 0xFF) > 0x90)
131
{
132
returnCode = 2;
133
break;
134
}
135
}
136
137
if (i == signOffset && (byteArray[signOffset] & CommonData.HIGHER_NIBBLE_MASK & 0xFF) > 0x90)
138
returnCode = 2;
139
140
// Check sign nibble
141
if ((byteArray[signOffset] & CommonData.LOWER_NIBBLE_MASK) < 0x0A)
142
{
143
returnCode++;
144
}
145
return returnCode;
146
}
147
148
// Assuming canOverwriteMostSignificantEvenNibble == false
149
/**
150
* Checks the validity of a Packed Decimal, return code indicating the status of the Packed Decimal. The most
151
* significant nibble cannot be overwritten.
152
*
153
* @param byteArray
154
* the source container array
155
* @param offset
156
* starting offset of the Packed Decimal
157
* @param precision
158
* precision of the Packed Decimal
159
* @param ignoreHighNibbleForEvenPrecision
160
* if true, ignore the high nibble in the case of even precision
161
* @return the condition code: 0 All digit codes and the sign valid 1 Sign invalid 2 At least one digit code invalid
162
* 3 Sign invalid and at least one digit code invalid
163
*
164
* @throws NullPointerException
165
* if <code>byteArray</code> is null
166
* @throws ArrayIndexOutOfBoundsException
167
* if an invalid array access occurs
168
*/
169
public static int checkPackedDecimal(byte[] byteArray, int offset,
170
int precision, boolean ignoreHighNibbleForEvenPrecision) {
171
return checkPackedDecimal(byteArray, offset, precision,
172
ignoreHighNibbleForEvenPrecision, false);
173
}
174
175
// Assuming canOverwriteMostSignificantEvenNibble == false
176
/**
177
* Checks the validity of a Packed Decimal, return code indicating the status of the Packed Decimal. Don't ignore
178
* the most significant nibble. The most significant nibble cannot be overwritten.
179
*
180
* @param byteArray
181
* the source container array
182
* @param offset
183
* starting offset of the Packed Decimal
184
* @param precision
185
* precision of the Packed Decimal
186
* @return the condition code: 0 All digit codes and the sign valid 1 Sign invalid 2 At least one digit code invalid
187
* 3 Sign invalid and at least one digit code invalid
188
*
189
* @throws NullPointerException
190
* if <code>byteArray</code> is null
191
* @throws ArrayIndexOutOfBoundsException
192
* if an invalid array access occurs
193
*/
194
public static int checkPackedDecimal(byte[] byteArray, int offset,
195
int precision) {
196
return checkPackedDecimal(byteArray, offset, precision, false, false);
197
}
198
199
private static void copyRemainingDigits(PackedDecimalOperand op1,
200
PackedDecimalOperand op2, boolean checkOverflow)
201
throws ArithmeticException {
202
PackedDecimalOperand sum = sum_threadLocal.get();
203
204
int bytes;
205
// copy any high order digits left in larger value to result
206
if (op1.currentOffset >= op1.offset) {
207
208
bytes = op1.currentOffset - op1.offset + 1;
209
int sumBytes = sum.currentOffset - sum.offset + 1;
210
if (bytes >= sumBytes) {
211
if (checkOverflow && bytes > sumBytes)
212
throw new ArithmeticException(
213
"Decimal overflow during addition/subtraction.");
214
else
215
bytes = sum.currentOffset - sum.offset + 1;
216
sum.currentOffset = sum.currentOffset - bytes + 1;
217
op1.currentOffset += -bytes + 1;
218
System.arraycopy(op1.byteArray, op1.currentOffset,
219
sum.byteArray, sum.currentOffset, bytes);
220
if (sum.precision % 2 == 0) {
221
byte highNibble = (byte) (sum.byteArray[sum.currentOffset] & CommonData.HIGHER_NIBBLE_MASK);
222
if (checkOverflow && bytes == sumBytes
223
&& highNibble != 0x00)
224
throw new ArithmeticException(
225
"Decimal overflow during addition/subtraction.");
226
else
227
sum.byteArray[sum.currentOffset] &= CommonData.LOWER_NIBBLE_MASK;
228
}
229
} else {
230
sum.currentOffset = sum.currentOffset - bytes + 1;
231
System.arraycopy(op1.byteArray, op1.offset, sum.byteArray,
232
sum.currentOffset, bytes);
233
}
234
sum.currentOffset--;
235
236
}
237
// pad high order result bytes with zeros
238
if (sum.currentOffset >= sum.offset) {
239
bytes = sum.currentOffset - sum.offset + 1;
240
Arrays.fill(sum.byteArray, sum.offset, sum.offset + bytes, CommonData.PACKED_ZERO);
241
}
242
}
243
244
/**
245
* Add two Packed Decimals in byte arrays. The sign of an input Packed Decimal is assumed to be positive unless
246
* the sign nibble contains one of the negative sign codes, in which case the sign of the respective input Packed
247
* Decimal is interpreted as negative.
248
*
249
* @param result
250
* byte array that will hold the sum of the two operand Packed Decimals
251
* @param resultOffset
252
* offset into <code>result</code> where the sum Packed Decimal begins
253
* @param resultPrecision
254
* number of Packed Decimal digits for the sum. Maximum valid precision is 253
255
* @param op1Decimal
256
* byte array that holds the first operand Packed Decimal.
257
* @param op1Offset
258
* offset into <code>op1Decimal</code> where the Packed Decimal. is located
259
* @param op1Precision
260
* number of Packed Decimal digits for the first operand. Maximum valid precision is 253
261
* @param op2Decimal
262
* byte array that holds the second operand Packed Decimal
263
* @param op2Offset
264
* offset into <code>op2Decimal</code> where the Packed Decimal is located
265
* @param op2Precision
266
* number of Packed Decimal digits for the second operand. Maximum valid precision is 253
267
* @param checkOverflow
268
* check for overflow
269
*
270
* @throws NullPointerException
271
* if any of the byte arrays are null
272
* @throws ArrayIndexOutOfBoundsException
273
* if an invalid array access occurs
274
* @throws ArithmeticException
275
* if an overflow occurs during the computation of the sum
276
*/
277
public static void addPackedDecimal(byte[] result, int resultOffset,
278
int resultPrecision, byte[] op1Decimal, int op1Offset,
279
int op1Precision, byte[] op2Decimal, int op2Offset,
280
int op2Precision, boolean checkOverflow) throws ArithmeticException {
281
if ((resultOffset + ((resultPrecision / 2) + 1) > result.length) || (resultOffset < 0))
282
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
283
"addPackedDecimal is trying to access result[" + resultOffset + "] to result[" + (resultOffset + (resultPrecision / 2)) + "]" +
284
" but valid indices are from 0 to " + (result.length - 1) + ".");
285
286
if ((op1Offset < 0) || (op1Offset + ((op1Precision / 2) + 1) > op1Decimal.length))
287
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
288
"addPackedDecimal is trying to access op1Decimal[" + op1Offset + "] to op1Decimal[" + (op1Offset + (op1Precision / 2)) + "]" +
289
" but valid indices are from 0 to " + (op1Decimal.length - 1) + ".");
290
291
if ((op2Offset < 0) || (op2Offset + ((op2Precision / 2) + 1) > op2Decimal.length))
292
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
293
"addPackedDecimal is trying to access op2Decimal[" + op2Offset + "] to op2Decimal[" + (op2Offset + (op2Precision / 2)) + "]" +
294
" but valid indices are from 0 to " + (op2Decimal.length - 1) + ".");
295
296
addPackedDecimal_(result, resultOffset, resultPrecision, op1Decimal, op1Offset,
297
op1Precision, op2Decimal, op2Offset, op2Precision, checkOverflow);
298
}
299
300
private static void addPackedDecimal_(byte[] result, int resultOffset,
301
int resultPrecision, byte[] op1Decimal, int op1Offset,
302
int op1Precision, byte[] op2Decimal, int op2Offset,
303
int op2Precision, boolean checkOverflow) throws ArithmeticException {
304
// capture result type information
305
sum_threadLocal.get().setSumOperand(result, resultOffset,
306
resultPrecision);
307
// ignore leading zeros in operand values
308
op1_threadLocal.get().setOperand(op1Decimal, op1Offset, op1Precision);
309
op2_threadLocal.get().setOperand(op2Decimal, op2Offset, op2Precision);
310
// add values
311
computeValue(checkOverflow);
312
}
313
314
/**
315
* Subtracts two Packed Decimals in byte arrays. The sign of an input Packed Decimal is assumed to be positive
316
* unless the sign nibble contains one of the negative sign codes, in which case the sign of the respective input
317
* Packed Decimal is interpreted as negative.
318
*
319
* @param result
320
* byte array that will hold the difference of the two operand Packed Decimals
321
* @param resultOffset
322
* offset into <code>result</code> where the result Packed Decimal is located
323
* @param resultPrecision
324
* number of Packed Decimal digits for the result. Maximum valid precision is 253
325
* @param op1Decimal
326
* byte array that holds the first Packed Decimal operand
327
* @param op1Offset
328
* offset into <code>op1Decimal</code> where the first operand is located
329
* @param op1Precision
330
* number of Packed Decimal digits for the first operand. Maximum valid precision is 253
331
* @param op2Decimal
332
* byte array that holds the second Packed Decimal operand
333
* @param op2Offset
334
* offset into <code>op2Decimal</code> where the second operand is located
335
* @param op2Precision
336
* number of Packed Decimal digits for the second operand. Maximum valid precision is 253
337
* @param checkOverflow
338
* check for overflow
339
*
340
* @throws NullPointerException
341
* if any of the byte arrays are null
342
* @throws ArrayIndexOutOfBoundsException
343
* if an invalid array access occurs
344
* @throws ArithmeticException
345
* if an overflow occurs during the computation of the difference
346
*/
347
public static void subtractPackedDecimal(byte[] result, int resultOffset,
348
int resultPrecision, byte[] op1Decimal, int op1Offset,
349
int op1Precision, byte[] op2Decimal, int op2Offset,
350
int op2Precision, boolean checkOverflow) throws ArithmeticException {
351
if ((resultOffset + ((resultPrecision / 2) + 1) > result.length) || (resultOffset < 0))
352
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
353
"subtractPackedDecimal is trying to access result[" + resultOffset + "] to result[" + (resultOffset + (resultPrecision / 2)) + "]" +
354
" but valid indices are from 0 to " + (result.length - 1) + ".");
355
356
if ((op1Offset < 0) || (op1Offset + ((op1Precision / 2) + 1) > op1Decimal.length))
357
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
358
"subtractPackedDecimal is trying to access op1Decimal[" + op1Offset + "] to op1Decimal[" + (op1Offset + (op1Precision / 2)) + "]" +
359
" but valid indices are from 0 to " + (op1Decimal.length - 1) + ".");
360
361
if ((op2Offset < 0) || (op2Offset + ((op2Precision / 2) + 1) > op2Decimal.length))
362
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
363
"subtractPackedDecimal is trying to access op2Decimal[" + op2Offset + "] to op2Decimal[" + (op2Offset + (op2Precision / 2)) + "]" +
364
" but valid indices are from 0 to " + (op2Decimal.length - 1) + ".");
365
366
subtractPackedDecimal_(result, resultOffset, resultPrecision, op1Decimal, op1Offset,
367
op1Precision, op2Decimal, op2Offset, op2Precision, checkOverflow);
368
}
369
370
private static void subtractPackedDecimal_(byte[] result, int resultOffset,
371
int resultPrecision, byte[] op1Decimal, int op1Offset,
372
int op1Precision, byte[] op2Decimal, int op2Offset,
373
int op2Precision, boolean checkOverflow) throws ArithmeticException {
374
375
PackedDecimalOperand sum = sum_threadLocal.get();
376
PackedDecimalOperand op1 = op1_threadLocal.get();
377
PackedDecimalOperand op2 = op2_threadLocal.get();
378
379
// capture result type information
380
sum.setSumOperand(result, resultOffset, resultPrecision);
381
// ignore leading zeros in operand values
382
op1.setOperand(op1Decimal, op1Offset, op1Precision);
383
op2.setOperand(op2Decimal, op2Offset, op2Precision);
384
// change op2 sign for subtraction
385
if ((op2.sign & CommonData.LOWER_NIBBLE_MASK) == CommonData.PACKED_PLUS)
386
op2.sign = (op2.sign & CommonData.HIGHER_NIBBLE_MASK)
387
| CommonData.PACKED_MINUS;
388
else
389
op2.sign = (op2.sign & CommonData.HIGHER_NIBBLE_MASK)
390
| CommonData.PACKED_PLUS;
391
// add values
392
computeValue(checkOverflow);
393
}
394
395
/**
396
* Create a positive Packed Decimal representation of zero.
397
*
398
* @param byteArray
399
* byte array which will hold the packed zero
400
* @param offset
401
* offset into <code>toBytes</code> where the packed zero begins
402
* @param len
403
* length of the packed zero. Maximum valid length is 253
404
*
405
* @throws NullPointerException
406
* if <code>toBytes</code> is null
407
* @throws ArrayIndexOutOfBoundsException
408
* if an invalid array access occurs
409
*/
410
public static void setPackedZero(byte[] byteArray, int offset, int len) {
411
int byteLen = CommonData.getPackedByteCount(len);
412
Arrays.fill(byteArray, offset, offset + byteLen - 1, CommonData.PACKED_ZERO);
413
byteArray[offset + byteLen - 1] = CommonData.PACKED_PLUS;
414
}
415
416
private static void computeSum(PackedDecimalOperand op1,
417
PackedDecimalOperand op2, boolean checkOverflow)
418
throws ArithmeticException {
419
420
PackedDecimalOperand sum = sum_threadLocal.get();
421
422
boolean carry;// add op2 sign digit to op1 sign digit
423
sum.indexValue = ((op1.signDigit + op2.signDigit) << 1) & 0x3FF;
424
sum.byteValue = CommonData.getPackedSumValues(sum.indexValue);
425
carry = sum.byteValue < op1.signDigit;
426
sum.byteArray[sum.signOffset] = (byte) (sum.byteValue | (op1.sign & CommonData.LOWER_NIBBLE_MASK));
427
428
// add op2 digits to op1 digits
429
for (; op2.currentOffset >= op2.offset
430
&& sum.currentOffset >= sum.offset; op2.currentOffset -= 1, op1.currentOffset -= 1, sum.currentOffset -= 1) {
431
if (checkOverflow && sum.currentOffset < sum.offset) {
432
throw new ArithmeticException(
433
"Decimal overflow in addPackedDecimal.");
434
}
435
;
436
op1.byteValue = op1.byteArray[op1.currentOffset]
437
& CommonData.INTEGER_MASK;
438
op2.byteValue = op2.byteArray[op2.currentOffset]
439
& CommonData.INTEGER_MASK;
440
op1.indexValue = op1.byteValue
441
+ (op1.byteValue & CommonData.HIGHER_NIBBLE_MASK);
442
op2.indexValue = op2.byteValue
443
+ (op2.byteValue & CommonData.HIGHER_NIBBLE_MASK);
444
sum.indexValue = op1.indexValue + op2.indexValue;
445
if (carry)
446
sum.byteValue = CommonData
447
.getPackedSumPlusOneValues(sum.indexValue);
448
else
449
sum.byteValue = CommonData.getPackedSumValues(sum.indexValue);
450
carry = (sum.byteValue & CommonData.INTEGER_MASK) < ((op1.byteValue & CommonData.INTEGER_MASK) + (op2.byteValue & CommonData.INTEGER_MASK));
451
sum.byteArray[sum.currentOffset] = (byte) (sum.byteValue);
452
}
453
// if carry, add one to remaining high order digits from op1
454
for (; carry && op1.currentOffset >= op1.offset
455
&& sum.currentOffset >= sum.offset; op1.currentOffset -= 1, sum.currentOffset -= 1) {
456
if (checkOverflow && sum.currentOffset < sum.offset) {
457
throw new ArithmeticException(
458
"Decimal overflow in addPackedDecimal");
459
}
460
sum.byteValue = CommonData
461
.getPackedAddOneValues(op1.byteArray[op1.currentOffset])
462
& CommonData.INTEGER_MASK;
463
carry = (sum.byteValue == 0x00);
464
sum.byteArray[sum.currentOffset] = (byte) (sum.byteValue);
465
}
466
if (sum.currentOffset < sum.offset) // reached the end
467
{
468
if ((carry && checkOverflow)
469
|| (checkOverflow && op1.currentOffset >= op1.offset))
470
throw new ArithmeticException(
471
"Decimal overflow in addPackedDecimal");
472
else if (sum.precision % 2 == 0) {
473
if ((byte) (sum.byteArray[sum.offset] & CommonData.HIGHER_NIBBLE_MASK) > (byte) 0x00
474
&& checkOverflow)
475
throw new ArithmeticException(
476
"Decimal overflow in addPackedDecimal");
477
sum.byteArray[sum.offset] &= CommonData.LOWER_NIBBLE_MASK;
478
}
479
return;
480
}
481
// if still carry, add high order one to sum
482
if (carry) { // carry
483
sum.byteArray[sum.currentOffset] = 1;
484
sum.currentOffset -= 1;
485
}
486
// copy any remaining digits
487
copyRemainingDigits(op1, op2, checkOverflow);
488
}
489
490
private static void computeDifference(PackedDecimalOperand op1,
491
PackedDecimalOperand op2, boolean checkOverflow)
492
throws ArithmeticException {
493
494
PackedDecimalOperand sum = sum_threadLocal.get();
495
496
boolean borrow;
497
// compute difference from sign byte
498
borrow = op1.signDigit < op2.signDigit;
499
500
sum.byteValue = Math.abs((op1.signDigit >> 4) - (op2.signDigit >> 4)
501
+ 10) % 10;
502
sum.byteArray[sum.signOffset] = (byte) ((sum.byteValue << 4) | (op1.sign & CommonData.LOWER_NIBBLE_MASK));
503
504
// compute op1 digit values - op2 digit values ;
505
for (op2.currentOffset = op2.signOffset - 1, op1.currentOffset = op1.signOffset - 1; op2.currentOffset >= op2.offset
506
&& sum.currentOffset >= sum.offset; op2.currentOffset -= 1, op1.currentOffset -= 1, sum.currentOffset -= 1) {
507
if (checkOverflow && sum.currentOffset < sum.offset) {
508
throw new ArithmeticException(
509
"Decimal overflow in subtractPackedDecimal");
510
}
511
512
op1.byteValue = op1.byteArray[op1.currentOffset]
513
& CommonData.INTEGER_MASK;
514
op2.byteValue = op2.byteArray[op2.currentOffset]
515
& CommonData.INTEGER_MASK;
516
op1.indexValue = op1.byteValue
517
+ (op1.byteValue & CommonData.HIGHER_NIBBLE_MASK);
518
op2.indexValue = op2.byteValue
519
+ (op2.byteValue & CommonData.HIGHER_NIBBLE_MASK);
520
sum.indexValue = (op1.indexValue - op2.indexValue) & 0x3FF;
521
if (borrow)
522
sum.byteValue = CommonData
523
.getPackedDifferenceMinusOneValues(sum.indexValue);
524
else
525
sum.byteValue = CommonData
526
.getPackedDifferenceValues(sum.indexValue);
527
borrow = (sum.byteValue & CommonData.INTEGER_MASK) > ((op1.byteValue & CommonData.INTEGER_MASK) - (op2.byteValue & CommonData.INTEGER_MASK));
528
if (sum.currentOffset >= sum.offset)
529
sum.byteArray[sum.currentOffset] = (byte) (sum.byteValue);
530
}
531
// if borrow, subtract one from remaining high order digits
532
for (; borrow && op1.currentOffset >= op1.offset
533
&& sum.currentOffset >= sum.offset; op1.currentOffset -= 1, sum.currentOffset -= 1) {
534
if (checkOverflow && sum.currentOffset < sum.offset) {
535
throw new ArithmeticException(
536
"Decimal overflow in subtractPackedDecimal");
537
}
538
sum.byteValue = CommonData
539
.getPackedBorrowOneValues(op1.byteArray[op1.currentOffset])
540
& CommonData.INTEGER_MASK;
541
borrow = (sum.byteValue == 0x99);
542
if (sum.currentOffset >= sum.offset)
543
sum.byteArray[sum.currentOffset] = (byte) (sum.byteValue);
544
}
545
546
copyRemainingDigits(op1, op2, checkOverflow);
547
}
548
549
private static void computeValue(boolean checkOverflow)
550
throws ArithmeticException {
551
552
PackedDecimalOperand sum = sum_threadLocal.get();
553
PackedDecimalOperand op1 = op1_threadLocal.get();
554
PackedDecimalOperand op2 = op2_threadLocal.get();
555
556
if ((op1.sign & CommonData.LOWER_NIBBLE_MASK) == (op2.sign & CommonData.LOWER_NIBBLE_MASK)) {
557
// signs are same, compute sum of values
558
// add less bytes to more bytes
559
if (op1.bytes < op2.bytes)
560
computeSum(op2, op1, checkOverflow);
561
else
562
computeSum(op1, op2, checkOverflow);
563
} else { // signs are different, compute difference of values
564
// subtract smaller value from larger value so we will always
565
// have one to borrow
566
if (op1.bytes < op2.bytes)
567
computeDifference(op2, op1, checkOverflow); // op2 has more
568
// non-zero bytes
569
else if (op1.bytes > op2.bytes)
570
computeDifference(op1, op2, checkOverflow); // op2 has more
571
// non-zero bytes
572
else {
573
// compare values to find which is larger.
574
// adjust offsets at same time - difference between equal bytes
575
// is 0
576
findDifference: {
577
for (; op1.offset < op1.signOffset; op1.offset += 1, op2.offset += 1) {
578
op1.byteValue = op1.byteArray[op1.offset];
579
op2.byteValue = op2.byteArray[op2.offset];
580
if (op1.byteValue != op2.byteValue)
581
break findDifference;
582
}
583
op1.byteValue = op1.byteArray[op1.offset]
584
& CommonData.HIGHER_NIBBLE_MASK;
585
op2.byteValue = op2.byteArray[op2.offset]
586
& CommonData.HIGHER_NIBBLE_MASK;
587
if (op1.byteValue == op2.byteValue) {
588
// values are equal, difference is zero
589
setPackedZero(sum.byteArray, sum.offset, sum.precision);
590
return;
591
}
592
}
593
if ((op1.byteValue & CommonData.INTEGER_MASK) > (op2.byteValue & CommonData.INTEGER_MASK))
594
computeDifference(op1, op2, checkOverflow);
595
else
596
computeDifference(op2, op1, checkOverflow);
597
}
598
}
599
}
600
601
// The implementations of multiply, divide and remainder are based on
602
// BigDecimal
603
// for simplicity and also because it has been shown that they have
604
// acceptable performance.
605
606
private static final int MULTIPLY = 1, DIVIDE = 2, REMAINDER = 3;
607
608
/**
609
* Multiplies two Packed Decimals in byte arrays. The sign of an input Packed Decimal is assumed to be positive
610
* unless the sign nibble contains one of the negative sign codes, in which case the sign of the respective input
611
* Packed Decimal is interpreted as negative.
612
*
613
* @param result
614
* byte array that will hold the product Packed Decimal
615
* @param resultOffset
616
* offset into <code>result</code> where the product Packed Decimal is located
617
* @param resultPrecision
618
* the length (number of digits) of the product Packed Decimal. Maximum valid precision is 253
619
* @param op1Decimal
620
* byte array that will hold the multiplicand Packed Decimal
621
* @param op1Offset
622
* offset into <code>op1Decimal</code> where the multiplicand is located
623
* @param op1Precision
624
* the length (number of digits) of the multiplicand Packed Decimal. Maximum valid precision is 253
625
* @param op2Decimal
626
* byte array that will hold the multiplier
627
* @param op2Offset
628
* offset into <code>op2Decimal</code> where the multiplier is located
629
* @param op2Precision
630
* the length (number of digits) of the multiplier Packed Decimal. Maximum valid precision is 253
631
* @param checkOverflow
632
* if set to true, Packed Decimals are validated before multiplication and an
633
* <code>IllegalArgumentException</code> or <code>ArithmeticException</code> may be thrown. If not, the
634
* result can be invalid
635
*
636
* @throws NullPointerException
637
* if any of the byte arrays are null
638
* @throws ArrayIndexOutOfBoundsException
639
* if an invalid array access occurs
640
* @throws IllegalArgumentException
641
* if an overflow occurs during multiplication
642
* @throws ArithmeticException
643
* if any of the Packed Decimal operands are invalid
644
*/
645
public static void multiplyPackedDecimal(byte[] result, int resultOffset,
646
int resultPrecision, byte[] op1Decimal, int op1Offset,
647
int op1Precision, // multiplicand
648
byte[] op2Decimal, int op2Offset, int op2Precision, // multiplier
649
boolean checkOverflow) {
650
if ((resultOffset + ((resultPrecision / 2) + 1) > result.length) || (resultOffset < 0))
651
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
652
"multiplyPackedDecimal is trying to access result[" + resultOffset + "] to result[" + (resultOffset + (resultPrecision / 2)) + "]" +
653
" but valid indices are from 0 to " + (result.length - 1) + ".");
654
655
if ((op1Offset < 0) || (op1Offset + ((op1Precision / 2) + 1) > op1Decimal.length))
656
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
657
"multiplyPackedDecimal is trying to access op1Decimal[" + op1Offset + "] to op1Decimal[" + (op1Offset + (op1Precision / 2)) + "]" +
658
" but valid indices are from 0 to " + (op1Decimal.length - 1) + ".");
659
660
if ((op2Offset < 0) || (op2Offset + ((op2Precision / 2) + 1) > op2Decimal.length))
661
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
662
"multiplyPackedDecimal is trying to access op2Decimal[" + op2Offset + "] to op2Decimal[" + (op2Offset + (op2Precision / 2)) + "]" +
663
" but valid indices are from 0 to " + (op2Decimal.length - 1) + ".");
664
665
multiplyPackedDecimal_(result, resultOffset, resultPrecision, op1Decimal, op1Offset,
666
op1Precision, op2Decimal, op2Offset, op2Precision, checkOverflow);
667
}
668
669
private static void multiplyPackedDecimal_(byte[] result, int resultOffset,
670
int resultPrecision, byte[] op1Decimal, int op1Offset,
671
int op1Precision, // multiplicand
672
byte[] op2Decimal, int op2Offset, int op2Precision, // multiplier
673
boolean checkOverflow) {
674
packedDecimalBinaryOp(MULTIPLY, result, resultOffset, resultPrecision,
675
op1Decimal, op1Offset, op1Precision, op2Decimal, op2Offset,
676
op2Precision, checkOverflow);
677
}
678
679
/**
680
* Divides two Packed Decimals is byte arrays. The sign of an input Packed Decimal is assumed to be positive
681
* unless the sign nibble contains one of the negative sign codes, in which case the sign of the respective input
682
* Packed Decimal is interpreted as negative.
683
*
684
* @param result
685
* byte array that will hold the quotient Packed Decimal
686
* @param resultOffset
687
* offset into <code>result</code> where the quotient Packed Decimal is located
688
* @param resultPrecision
689
* the length (number of digits) of the quotient Packed Decimal. Maximum valid precision is 253
690
* @param op1Decimal
691
* byte array that will hold the dividend Packed Decimal
692
* @param op1Offset
693
* offset into <code>op1Decimal</code> where the dividend is located
694
* @param op1Precision
695
* the length (number of digits) of the dividend Packed Decimal. Maximum valid precision is 253
696
* @param op2Decimal
697
* byte array that will hold the divisor
698
* @param op2Offset
699
* offset into <code>op2Decimal</code> where the divisor is located
700
* @param op2Precision
701
* the length (number of digits) of the divisor Packed Decimal. Maximum valid precision is 253
702
* @param checkOverflow
703
* if set to true, Packed Decimals are validated before division and an
704
* <code>IllegalArgumentException</code> or <code>ArithmeticException</code> may be thrown. If not, the
705
* result can be invalid
706
*
707
* @throws NullPointerException
708
* if any of the byte arrays are null
709
* @throws ArrayIndexOutOfBoundsException
710
* if an invalid array access occurs
711
* @throws IllegalArgumentException
712
* if an overflow occurs during division
713
* @throws ArithmeticException
714
* if any of the Packed Decimal operands are invalid
715
*/
716
public static void dividePackedDecimal(byte[] result, int resultOffset,
717
int resultPrecision, byte[] op1Decimal, int op1Offset,
718
int op1Precision, byte[] op2Decimal, int op2Offset,
719
int op2Precision, boolean checkOverflow) {
720
if ((resultOffset + ((resultPrecision / 2) + 1) > result.length) || (resultOffset < 0))
721
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
722
"dividePackedDecimal is trying to access result[" + resultOffset + "] to result[" + (resultOffset + (resultPrecision / 2)) + "]" +
723
" but valid indices are from 0 to " + (result.length - 1) + ".");
724
725
if ((op1Offset < 0) || (op1Offset + ((op1Precision / 2) + 1) > op1Decimal.length))
726
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
727
"dividePackedDecimal is trying to access op1Decimal[" + op1Offset + "] to op1Decimal[" + (op1Offset + (op1Precision / 2)) + "]" +
728
" but valid indices are from 0 to " + (op1Decimal.length - 1) + ".");
729
730
if ((op2Offset < 0) || (op2Offset + ((op2Precision / 2) + 1) > op2Decimal.length))
731
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
732
"dividePackedDecimal is trying to access op2Decimal[" + op2Offset + "] to op2Decimal[" + (op2Offset + (op2Precision / 2)) + "]" +
733
" but valid indices are from 0 to " + (op2Decimal.length - 1) + ".");
734
735
dividePackedDecimal_(result, resultOffset, resultPrecision, op1Decimal, op1Offset,
736
op1Precision, op2Decimal, op2Offset, op2Precision, checkOverflow);
737
}
738
739
private static void dividePackedDecimal_(byte[] result, int resultOffset,
740
int resultPrecision, byte[] op1Decimal, int op1Offset,
741
int op1Precision, byte[] op2Decimal, int op2Offset,
742
int op2Precision, boolean checkOverflow) {
743
packedDecimalBinaryOp(DIVIDE, result, resultOffset, resultPrecision,
744
op1Decimal, op1Offset, op1Precision, op2Decimal, op2Offset,
745
op2Precision, checkOverflow);
746
747
}
748
749
/**
750
* Calculates the remainder resulting from the division of two Packed Decimals in byte arrays. The sign of an input
751
* Packed Decimal is assumed to be positive unless the sign nibble contains one of the negative sign codes, in
752
* which case the sign of the respective input Packed Decimal is interpreted as negative.
753
*
754
* @param result
755
* byte array that will hold the remainder Packed Decimal
756
* @param resultOffset
757
* offset into <code>result</code> where the remainder Packed Decimal is located
758
* @param resultPrecision
759
* number of Packed Decimal digits for the remainder. Maximum valid precision is 253
760
* @param op1Decimal
761
* byte array that will hold the dividend Packed Decimal
762
* @param op1Offset
763
* offset into <code>op1Decimal</code> where the dividend is located
764
* @param op1Precision
765
* number of Packed Decimal digits for the dividend. Maximum valid precision is 253
766
* @param op2Decimal
767
* byte array that will hold the divisor
768
* @param op2Offset
769
* offset into <code>op2Decimal</code> where the divisor is located
770
* @param op2Precision
771
* number of Packed Decimal digits for the divisor. Maximum valid precision is 253
772
* @param checkOverflow
773
* if set to true, Packed Decimals are validated before division and an
774
* <code>IllegalArgumentException</code> or <code>ArithmeticException</code> may be thrown. If not, the
775
* result can be invalid
776
*
777
* @throws NullPointerException
778
* if any of the byte arrays are null
779
* @throws ArrayIndexOutOfBoundsException
780
* if an invalid array access occurs
781
* @throws IllegalArgumentException
782
* if an overflow occurs during division
783
* @throws ArithmeticException
784
* if any of the Packed Decimal operands are invalid
785
*/
786
public static void remainderPackedDecimal(byte[] result, int resultOffset,
787
int resultPrecision, byte[] op1Decimal, int op1Offset,
788
int op1Precision, byte[] op2Decimal, int op2Offset,
789
int op2Precision, boolean checkOverflow) {
790
if ((resultOffset + ((resultPrecision / 2) + 1) > result.length) || (resultOffset < 0))
791
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
792
"remainderPackedDecimal is trying to access result[" + resultOffset + "] to result[" + (resultOffset + (resultPrecision / 2)) + "]" +
793
" but valid indices are from 0 to " + (result.length - 1) + ".");
794
795
if ((op1Offset < 0) || (op1Offset + ((op1Precision / 2) + 1) > op1Decimal.length))
796
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
797
"remainderPackedDecimal is trying to access op1Decimal[" + op1Offset + "] to op1Decimal[" + (op1Offset + (op1Precision / 2)) + "]" +
798
" but valid indices are from 0 to " + (op1Decimal.length - 1) + ".");
799
800
if ((op2Offset < 0) || (op2Offset + ((op2Precision / 2) + 1) > op2Decimal.length))
801
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
802
"remainderPackedDecimal is trying to access op2Decimal[" + op2Offset + "] to op2Decimal[" + (op2Offset + (op2Precision / 2)) + "]" +
803
" but valid indices are from 0 to " + (op2Decimal.length - 1) + ".");
804
805
remainderPackedDecimal_(result, resultOffset, resultPrecision, op1Decimal, op1Offset,
806
op1Precision, op2Decimal, op2Offset, op2Precision, checkOverflow);
807
}
808
private static void remainderPackedDecimal_(byte[] result, int resultOffset,
809
int resultPrecision, byte[] op1Decimal, int op1Offset,
810
int op1Precision, byte[] op2Decimal, int op2Offset,
811
int op2Precision, boolean checkOverflow) {
812
packedDecimalBinaryOp(REMAINDER, result, resultOffset, resultPrecision,
813
op1Decimal, op1Offset, op1Precision, op2Decimal, op2Offset,
814
op2Precision, checkOverflow);
815
}
816
817
private static BigInteger getBigInteger(byte[] pd, int offset, int length) {
818
int end = offset + length - 1;
819
StringBuilder sb = new StringBuilder();
820
821
if ((pd[end] & CommonData.LOWER_NIBBLE_MASK) == 0x0B
822
|| (pd[end] & CommonData.LOWER_NIBBLE_MASK) == 0x0D)
823
sb.append('-');
824
825
for (int i = offset; i < end; i++) {
826
sb.append((char) ('0' + (pd[i] >> 4 & CommonData.LOWER_NIBBLE_MASK)));
827
sb.append((char) ('0' + (pd[i] & CommonData.LOWER_NIBBLE_MASK)));
828
}
829
sb.append((char) ('0' + (pd[end] >> 4 & CommonData.LOWER_NIBBLE_MASK)));
830
return new BigInteger(sb.toString());
831
}
832
833
private static void putBigInteger(byte[] pd, int offset, int length,
834
BigInteger bigInt, boolean checkOverflow)
835
throws ArithmeticException {
836
int end = offset + length - 1;
837
838
// could use abs(), but want to avoid creating another BigInteger object
839
char[] chars = bigInt.toString().toCharArray();
840
boolean neg = chars[0] == '-';
841
842
int charStart = neg ? 1 : 0;
843
int charEnd = chars.length - 1;
844
845
pd[end--] = (byte) ((neg ? 0x0D : 0x0C) | (chars[charEnd--] - '0' << 4));
846
847
while (end >= offset) {
848
byte b = 0;
849
if (charEnd >= charStart) {
850
b = (byte) (chars[charEnd--] - '0');
851
if (charEnd >= charStart) {
852
b |= chars[charEnd--] - '0' << 4;
853
}
854
}
855
pd[end--] = b;
856
}
857
858
if (checkOverflow && charEnd < charStart) {
859
while (charEnd >= charStart) {
860
if (chars[charEnd--] != '0') {
861
throw new ArithmeticException(
862
"Packed Decimal overflow during multiplication/division, non-zero digits lost");
863
}
864
}
865
}
866
}
867
868
private static void zeroTopNibbleIfEven(byte[] bytes, int offset, int prec) {
869
if (prec % 2 == 0)
870
bytes[offset] &= CommonData.LOWER_NIBBLE_MASK;
871
}
872
873
private static void packedDecimalBinaryOp(int op, byte[] result,
874
int offsetResult, int precResult, byte[] op1, int op1Offset,
875
int precOp1, byte[] op2, int op2Offset, int precOp2,
876
boolean checkOverflow) {
877
878
zeroTopNibbleIfEven(op1, op1Offset, precOp1);
879
zeroTopNibbleIfEven(op2, op2Offset, precOp2);
880
881
// check for long
882
switch (op) {
883
case MULTIPLY:
884
if (precOp1 + precOp2 <= 18 && precResult <= 18) {
885
long op1long = DecimalData.convertPackedDecimalToLong(op1,
886
op1Offset, precOp1, checkOverflow);
887
long op2long = DecimalData.convertPackedDecimalToLong(op2,
888
op2Offset, precOp2, checkOverflow);
889
long resultLong = op1long * op2long;
890
DecimalData.convertLongToPackedDecimal(resultLong, result,
891
offsetResult, precResult, checkOverflow);
892
if (resultLong == 0)
893
forceSign(result, offsetResult, precResult, op1, op1Offset,
894
precOp1, op2, op2Offset, precOp2);
895
return;
896
}
897
break;
898
case DIVIDE:
899
case REMAINDER:
900
if (precOp1 <= 18 && precOp2 <= 18 && precResult <= 18) {
901
long op1long = DecimalData.convertPackedDecimalToLong(op1,
902
op1Offset, precOp1, checkOverflow);
903
long op2long = DecimalData.convertPackedDecimalToLong(op2,
904
op2Offset, precOp2, checkOverflow);
905
long resultLong;
906
if (op == DIVIDE)
907
resultLong = op1long / op2long;
908
else
909
resultLong = op1long % op2long;
910
DecimalData.convertLongToPackedDecimal(resultLong, result,
911
offsetResult, precResult, checkOverflow);
912
if (resultLong == 0)
913
forceSign(result, offsetResult, precResult, op1, op1Offset,
914
precOp1, op2, op2Offset, precOp2);
915
return;
916
}
917
break;
918
}
919
920
// long is too small
921
BigInteger op1BigInt;
922
BigInteger op2BigInt;
923
try {
924
op1BigInt = getBigInteger(op1, op1Offset,
925
precisionToByteLength(precOp1));
926
op2BigInt = getBigInteger(op2, op2Offset,
927
precisionToByteLength(precOp2));
928
} catch (NumberFormatException e) {
929
if (checkOverflow)
930
throw new IllegalArgumentException("Invalid packed data value",
931
e);
932
return;
933
}
934
935
BigInteger resultBigInt = null;
936
switch (op) {
937
case MULTIPLY:
938
resultBigInt = op1BigInt.multiply(op2BigInt);
939
break;
940
case DIVIDE:
941
resultBigInt = op1BigInt.divide(op2BigInt);
942
break;
943
case REMAINDER:
944
resultBigInt = op1BigInt.remainder(op2BigInt);
945
break;
946
}
947
948
putBigInteger(result, offsetResult, precisionToByteLength(precResult),
949
resultBigInt, checkOverflow);
950
951
// force the sign because BigInteger will never produce negative zero
952
if (BigInteger.ZERO.equals(resultBigInt)) {
953
forceSign(result, offsetResult, precResult, op1, op1Offset,
954
precOp1, op2, op2Offset, precOp2);
955
}
956
}
957
958
/**
959
* Using BigInteger or long will never produce negative zero, so we need to
960
* make sure to set the correct sign code.
961
*/
962
private static void forceSign(byte[] result, int offsetResult,
963
int precResult, byte[] op1, int op1Offset, int precOp1, byte[] op2,
964
int op2Offset, int precOp2) {
965
966
int endOp1 = op1Offset + precisionToByteLength(precOp1) - 1;
967
int endOp2 = op2Offset + precisionToByteLength(precOp2) - 1;
968
int endResult = offsetResult + precisionToByteLength(precResult) - 1;
969
result[endResult] |= 0x0F;
970
result[endResult] &= signMask(op1[endOp1], op2[endOp2]);
971
}
972
973
private static int precisionToByteLength(int precision) {
974
return (precision + 2) / 2;
975
}
976
977
private static byte signMask(byte a, byte b) {
978
return (byte) (sign(a) * sign(b) > 0 ? 0xFC : 0xFD);
979
}
980
981
private static int sign(byte b) {
982
return (CommonData.getSign(b & CommonData.LOWER_NIBBLE_MASK) == CommonData.PACKED_MINUS) ? -1 : 1;
983
}
984
985
/**
986
* Checks if the first Packed Decimal operand is lesser than the second one.
987
*
988
* @param op1Decimal
989
* byte array that holds the first Packed Decimal operand
990
* @param op1Offset
991
* offset into <code>op1Decimal</code> where the first operand is located
992
* @param op1Precision
993
* number of Packed Decimal digits for the first operand
994
* @param op2Decimal
995
* byte array that holds the second Packed Decimal operand
996
* @param op2Offset
997
* offset into <code>op2Decimal</code> where the second operand is located
998
* @param op2Precision
999
* number of Packed Decimal digits for the second operand
1000
*
1001
* @return true if <code>op1Decimal &lt; op2Decimal</code>, false otherwise
1002
*
1003
* @throws NullPointerException
1004
* if any of the byte arrays are null
1005
* @throws ArrayIndexOutOfBoundsException
1006
* if an invalid array access occurs
1007
*/
1008
public static boolean lessThanPackedDecimal(byte[] op1Decimal,
1009
int op1Offset, int op1Precision, byte[] op2Decimal, int op2Offset,
1010
int op2Precision) {
1011
if ((op1Offset + ((op1Precision / 2) + 1) > op1Decimal.length) || (op1Offset < 0))
1012
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1013
"lessThanPackedDecimal is trying to access op1Decimal[" + op1Offset + "] to op1Decimal[" + (op1Offset + (op1Precision / 2)) + "]" +
1014
" but valid indices are from 0 to " + (op1Decimal.length - 1) + ".");
1015
1016
if ((op2Offset < 0) || (op2Offset + ((op2Precision / 2) + 1) > op2Decimal.length))
1017
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1018
"lessThanPackedDecimal is trying to access op2Decimal[" + op2Offset + "] to op2Decimal[" + (op2Offset + (op2Precision / 2)) + "]" +
1019
" but valid indices are from 0 to " + (op2Decimal.length - 1) + ".");
1020
1021
return lessThanPackedDecimal_(op1Decimal, op1Offset, op1Precision,
1022
op2Decimal, op2Offset, op2Precision);
1023
}
1024
1025
private static boolean lessThanPackedDecimal_(byte[] op1Decimal,
1026
int op1Offset, int op1Precision, byte[] op2Decimal, int op2Offset,
1027
int op2Precision) {
1028
1029
return greaterThanPackedDecimal_(op2Decimal, op2Offset, op2Precision, op1Decimal,
1030
op1Offset, op1Precision);
1031
}
1032
1033
/**
1034
* Checks if the first Packed Decimal operand is less than or equal to the second one.
1035
*
1036
* @param op1Decimal
1037
* byte array that holds the first Packed Decimal operand
1038
* @param op1Offset
1039
* offset into <code>op1Decimal</code> where the first operand is located
1040
* @param op1Precision
1041
* number of Packed Decimal digits for the first operand
1042
* @param op2Decimal
1043
* byte array that holds the second Packed Decimal operand
1044
* @param op2Offset
1045
* offset into <code>op2Decimal</code> where the second operand is located
1046
* @param op2Precision
1047
* number of Packed Decimal digits for the second operand
1048
*
1049
* @return true if <code>op1Decimal &lt;= op2Decimal</code>, false otherwise
1050
*
1051
* @throws NullPointerException
1052
* if any of the byte arrays are null
1053
* @throws ArrayIndexOutOfBoundsException
1054
* if an invalid array access occurs
1055
*/
1056
public static boolean lessThanOrEqualsPackedDecimal(byte[] op1Decimal,
1057
int op1Offset, int op1Precision, byte[] op2Decimal, int op2Offset,
1058
int op2Precision) {
1059
if ((op1Offset + ((op1Precision / 2) + 1) > op1Decimal.length) || (op1Offset < 0))
1060
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1061
"lessThanOrEqualsPackedDecimal is trying to access op1Decimal[" + op1Offset + "] to op1Decimal[" + (op1Offset + (op1Precision / 2)) + "]" +
1062
" but valid indices are from 0 to " + (op1Decimal.length - 1) + ".");
1063
1064
if ((op2Offset < 0) || (op2Offset + ((op2Precision / 2) + 1) > op2Decimal.length))
1065
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1066
"lessThanOrEqualsPackedDecimal is trying to access op2Decimal[" + op2Offset + "] to op2Decimal[" + (op2Offset + (op2Precision / 2)) + "]" +
1067
" but valid indices are from 0 to " + (op2Decimal.length - 1) + ".");
1068
1069
return lessThanOrEqualsPackedDecimal_(op1Decimal, op1Offset, op1Precision,
1070
op2Decimal, op2Offset, op2Precision);
1071
1072
}
1073
private static boolean lessThanOrEqualsPackedDecimal_(byte[] op1Decimal,
1074
int op1Offset, int op1Precision, byte[] op2Decimal, int op2Offset,
1075
int op2Precision) {
1076
return !greaterThanPackedDecimal_(op1Decimal, op1Offset, op1Precision,
1077
op2Decimal, op2Offset, op2Precision);
1078
}
1079
1080
/**
1081
* Checks if the first Packed Decimal operand is greater than the second one.
1082
*
1083
* @param op1Decimal
1084
* byte array that holds the first Packed Decimal operand
1085
* @param op1Offset
1086
* offset into <code>op1Decimal</code> where the first operand is located
1087
* @param op1Precision
1088
* number of Packed Decimal digits for the first operand
1089
* @param op2Decimal
1090
* byte array that holds the second Packed Decimal operand
1091
* @param op2Offset
1092
* offset into <code>op2Decimal</code> where the second operand is located
1093
* @param op2Precision
1094
* number of Packed Decimal digits for the second operand
1095
*
1096
* @return true if <code>op1Decimal &gt; op2Decimal</code>, false otherwise
1097
*
1098
* @throws NullPointerException
1099
* if any of the byte arrays are null
1100
* @throws ArrayIndexOutOfBoundsException
1101
* if an invalid array access occurs
1102
*/
1103
public static boolean greaterThanPackedDecimal(byte[] op1Decimal,
1104
int op1Offset, int op1Precision, byte[] op2Decimal, int op2Offset,
1105
int op2Precision) {
1106
if ((op1Offset + ((op1Precision / 2) + 1) > op1Decimal.length) || (op1Offset < 0))
1107
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1108
"greaterThanPackedDecimal is trying to access op1Decimal[" + op1Offset + "] to op1Decimal[" + (op1Offset + (op1Precision / 2)) + "]" +
1109
" but valid indices are from 0 to " + (op1Decimal.length - 1) + ".");
1110
1111
if ((op2Offset < 0) || (op2Offset + ((op2Precision / 2) + 1) > op2Decimal.length))
1112
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1113
"greaterThanPackedDecimal is trying to access op2Decimal[" + op2Offset + "] to op2Decimal[" + (op2Offset + (op2Precision / 2)) + "]" +
1114
" but valid indices are from 0 to " + (op2Decimal.length - 1) + ".");
1115
1116
return greaterThanPackedDecimal_(op1Decimal, op1Offset, op1Precision,
1117
op2Decimal, op2Offset, op2Precision);
1118
}
1119
1120
private static boolean greaterThanPackedDecimal_(byte[] op1Decimal,
1121
int op1Offset, int op1Precision, byte[] op2Decimal, int op2Offset,
1122
int op2Precision) {
1123
1124
if (op1Precision < 1 || op2Precision < 1)
1125
throw new IllegalArgumentException("Invalid Precision for an operand");
1126
1127
//boolean result = false;
1128
int op1End = op1Offset + precisionToByteLength(op1Precision) - 1;
1129
int op2End = op2Offset + precisionToByteLength(op2Precision) - 1;
1130
1131
//check signs, if a different signs we're done!
1132
byte op1Sign = CommonData.getSign((byte)(op1Decimal[op1End] & CommonData.LOWER_NIBBLE_MASK));
1133
byte op2Sign = CommonData.getSign((byte)(op2Decimal[op2End] & CommonData.LOWER_NIBBLE_MASK));
1134
1135
boolean isNegative = (op1Sign == CommonData.PACKED_MINUS) ? true : false;
1136
1137
//skip leading zeros
1138
for (; op1Offset < op1End && op1Decimal[op1Offset] == CommonData.PACKED_ZERO; op1Offset++)
1139
;
1140
for (; op2Offset < op2End && op2Decimal[op2Offset] == CommonData.PACKED_ZERO; op2Offset++)
1141
;
1142
1143
int op1Length = op1End - op1Offset;
1144
int op2Length = op2End - op2Offset;
1145
1146
if (op1Length + op2Length == 0)
1147
{
1148
int op1LastDigit = (op1Decimal[op1Offset] >> 4) & CommonData.LOWER_NIBBLE_MASK;
1149
int op2LastDigit = (op2Decimal[op2Offset] >> 4) & CommonData.LOWER_NIBBLE_MASK;
1150
if (op1LastDigit + op2LastDigit == 0) //both zeros
1151
return false;
1152
if (op1Sign < op2Sign)
1153
return true;
1154
else if (op1Sign > op2Sign)
1155
return false;
1156
if ((op1LastDigit > op2LastDigit && !isNegative) || (op1LastDigit < op2LastDigit && isNegative))
1157
return true;
1158
1159
return false;
1160
}
1161
1162
if (op1Sign < op2Sign)
1163
return true;
1164
else if (op1Sign > op2Sign)
1165
return false;
1166
1167
if ((op1Length > op2Length && !isNegative) || (op1Length < op2Length && isNegative))
1168
return true;
1169
else if ((op1Length < op2Length && !isNegative) || (op1Length > op2Length && isNegative))
1170
return false;
1171
1172
while(op1Offset < op1End && op2Offset < op2End)
1173
{
1174
int op1Byte = (op1Decimal[op1Offset] & 0xFF);
1175
int op2Byte = (op2Decimal[op2Offset] & 0xFF);
1176
int opDiff = op1Byte - op2Byte;
1177
1178
if ((opDiff < 0 && !isNegative) || (opDiff > 0 && isNegative))
1179
return false;
1180
else if ((opDiff > 0 && !isNegative) || (opDiff < 0 && isNegative))
1181
return true;
1182
1183
op1Offset++;
1184
op2Offset++;
1185
}
1186
//last digit
1187
int op1LastDigit = (op1Decimal[op1Offset] >> 4) & CommonData.LOWER_NIBBLE_MASK;
1188
int op2LastDigit = (op2Decimal[op2Offset] >> 4) & CommonData.LOWER_NIBBLE_MASK;
1189
1190
if ((op1LastDigit > op2LastDigit && !isNegative) || (op1LastDigit < op2LastDigit && isNegative))
1191
return true;
1192
1193
return false; //either equal or less than
1194
1195
}
1196
1197
/**
1198
* Checks if the first Packed Decimal operand is greater than or equal to the second one.
1199
*
1200
* @param op1Decimal
1201
* byte array that holds the first Packed Decimal operand
1202
* @param op1Offset
1203
* offset into <code>op1Decimal</code> where the first operand is located
1204
* @param op1Precision
1205
* number of Packed Decimal digits for the first operand
1206
* @param op2Decimal
1207
* byte array that holds the second Packed Decimal operand
1208
* @param op2Offset
1209
* offset into <code>op2Decimal</code> where the second operand is located
1210
* @param op2Precision
1211
* number of Packed Decimal digits for the second operand
1212
*
1213
* @return true if <code>op1Decimal &gt;= op2Decimal</code>, false otherwise
1214
*
1215
* @throws NullPointerException
1216
* if any of the byte arrays are null
1217
* @throws ArrayIndexOutOfBoundsException
1218
* if an invalid array access occurs
1219
*/
1220
public static boolean greaterThanOrEqualsPackedDecimal(byte[] op1Decimal,
1221
int op1Offset, int op1Precision, byte[] op2Decimal, int op2Offset,
1222
int op2Precision) {
1223
if ((op1Offset + ((op1Precision / 2) + 1) > op1Decimal.length) || (op1Offset < 0))
1224
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1225
"greaterThanOrEqualsPackedDecimal is trying to access op1Decimal[" + op1Offset + "] to op1Decimal[" + (op1Offset + (op1Precision / 2)) + "]" +
1226
" but valid indices are from 0 to " + (op1Decimal.length - 1) + ".");
1227
1228
if ((op2Offset < 0) || (op2Offset + ((op2Precision / 2) + 1) > op2Decimal.length))
1229
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1230
"greaterThanOrEqualsPackedDecimal is trying to access op2Decimal[" + op2Offset + "] to op2Decimal[" + (op2Offset + (op2Precision / 2)) + "]" +
1231
" but valid indices are from 0 to " + (op2Decimal.length - 1) + ".");
1232
1233
return greaterThanOrEqualsPackedDecimal_(op1Decimal, op1Offset, op1Precision,
1234
op2Decimal, op2Offset, op2Precision);
1235
}
1236
1237
private static boolean greaterThanOrEqualsPackedDecimal_(byte[] op1Decimal,
1238
int op1Offset, int op1Precision, byte[] op2Decimal, int op2Offset,
1239
int op2Precision) {
1240
return !lessThanPackedDecimal_(op1Decimal, op1Offset, op1Precision,
1241
op2Decimal, op2Offset, op2Precision);
1242
}
1243
1244
/**
1245
* Checks if the two Packed Decimal operands are equal.
1246
*
1247
* @param op1Decimal
1248
* byte array that holds the first Packed Decimal operand
1249
* @param op1Offset
1250
* offset into <code>op1Decimal</code> where the first operand is located
1251
* @param op1Precision
1252
* number of Packed Decimal digits for the first operand
1253
* @param op2Decimal
1254
* byte array that holds the second Packed Decimal operand
1255
* @param op2Offset
1256
* offset into <code>op2Decimal</code> where the second operand is located
1257
* @param op2Precision
1258
* number of Packed Decimal digits for the second operand
1259
*
1260
* @return true if op1Decimal == op2Decimal, false otherwise
1261
*
1262
* @throws NullPointerException
1263
* if any of the byte arrays are null
1264
* @throws ArrayIndexOutOfBoundsException
1265
* if an invalid array access occurs
1266
*/
1267
public static boolean equalsPackedDecimal(byte[] op1Decimal, int op1Offset,
1268
int op1Precision, byte[] op2Decimal, int op2Offset, int op2Precision) {
1269
if ((op1Offset + ((op1Precision / 2) + 1) > op1Decimal.length) || (op1Offset < 0))
1270
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1271
"equalsPackedDecimal is trying to access op1Decimal[" + op1Offset + "] to op1Decimal[" + (op1Offset + (op1Precision / 2)) + "]" +
1272
" but valid indices are from 0 to " + (op1Decimal.length - 1) + ".");
1273
1274
if ((op2Offset < 0) || (op2Offset + ((op2Precision / 2) + 1) > op2Decimal.length))
1275
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1276
"equalsPackedDecimal is trying to access op2Decimal[" + op2Offset + "] to op2Decimal[" + (op2Offset + (op2Precision / 2)) + "]" +
1277
" but valid indices are from 0 to " + (op2Decimal.length - 1) + ".");
1278
1279
return equalsPackedDecimal_(op1Decimal, op1Offset, op1Precision,
1280
op2Decimal, op2Offset, op2Precision);
1281
}
1282
1283
private static boolean equalsPackedDecimal_(byte[] op1Decimal, int op1Offset, int op1Precision,
1284
byte[] op2Decimal, int op2Offset, int op2Precision) {
1285
if (op1Precision < 1 || op2Precision < 1)
1286
throw new IllegalArgumentException("Invalid Precision for an operand");
1287
1288
int op1End = op1Offset + precisionToByteLength(op1Precision) - 1;
1289
int op2End = op2Offset + precisionToByteLength(op2Precision) - 1;
1290
1291
byte op1Sign = CommonData.getSign((byte) (op1Decimal[op1End] & CommonData.LOWER_NIBBLE_MASK));
1292
byte op2Sign = CommonData.getSign((byte) (op2Decimal[op2End] & CommonData.LOWER_NIBBLE_MASK));
1293
1294
boolean op1IsEven = op1Precision % 2 == 0;
1295
boolean op2IsEven = op2Precision % 2 == 0;
1296
1297
// Must handle the +0 and -0 case
1298
if (op1Sign != op2Sign)
1299
return checkZeroBetweenOpOffsetAndOpEnd (op1Decimal, op1Offset, op1End, op1IsEven, true) &&
1300
checkZeroBetweenOpOffsetAndOpEnd (op2Decimal, op2Offset, op2End, op2IsEven, true);
1301
1302
// Check if least significant digit is different
1303
if ((op1Decimal[op1End] & CommonData.HIGHER_NIBBLE_MASK) !=
1304
(op2Decimal[op2End] & CommonData.HIGHER_NIBBLE_MASK)) {
1305
return false;
1306
}
1307
1308
// Avoid decrementing if op1End == op1Offset || op2End == op2Offset
1309
if (op1End > op1Offset && op2End > op2Offset) {
1310
op1End--;
1311
op2End--;
1312
}
1313
1314
while (op1End > op1Offset && op2End > op2Offset) {
1315
// Check if intermediate digits are different
1316
if (op1Decimal[op1End] != op2Decimal[op2End])
1317
return false;
1318
1319
op1End--;
1320
op2End--;
1321
}
1322
1323
// At this point it is true that op1End == op1Offset || op2End == op2Offset
1324
if (op1End == op1Offset) {
1325
if (op1IsEven) {
1326
// Check if most significant digit is different
1327
if ((op1Decimal[op1End] & CommonData.LOWER_NIBBLE_MASK) ==
1328
(op2Decimal[op2End] & CommonData.LOWER_NIBBLE_MASK)) {
1329
return checkZeroBetweenOpOffsetAndOpEnd (op2Decimal, op2Offset, op2End, op2IsEven, !op2IsEven || op2End != op2Offset);
1330
}
1331
} else {
1332
// Check if two most significant digits are different
1333
if (op1Decimal[op1End] == op2Decimal[op2End])
1334
return checkZeroBetweenOpOffsetAndOpEnd (op2Decimal, op2Offset, op2End, op2IsEven, false);
1335
}
1336
} else {
1337
if (op2IsEven) {
1338
// Check if most significant digit is different
1339
if ((op1Decimal[op1End] & CommonData.LOWER_NIBBLE_MASK) ==
1340
(op2Decimal[op2End] & CommonData.LOWER_NIBBLE_MASK)) {
1341
return checkZeroBetweenOpOffsetAndOpEnd (op1Decimal, op1Offset, op1End, op1IsEven, !op1IsEven || op1End != op1Offset);
1342
}
1343
} else {
1344
// Check if two most significant digits are different
1345
if (op1Decimal[op1End] == op2Decimal[op2End])
1346
return checkZeroBetweenOpOffsetAndOpEnd (op1Decimal, op1Offset, op1End, op1IsEven, false);
1347
}
1348
}
1349
1350
return false;
1351
}
1352
1353
/**
1354
* Checks if the Packed Decimal digits between <code>opDecimal[opOffset]</code> and <code>opDecimal[opEnd]</code>
1355
* (inclusive depending on checkHighNibbleAtOpEnd) are all zeros.
1356
*
1357
* @param opDecimal
1358
* byte array that holds the Packed Decimal operand
1359
* @param opOffset
1360
* offset into <code>opDecimal</code> where the first byte of the Packed Decimal is located
1361
* @param opEnd
1362
* offset into <code>opDecimal</code> where the last byte to be checked is located
1363
* @param opIsEven
1364
* boolean is true if the <code>opDecimal</code> has even precision
1365
* @param checkHighNibbleAtOpEnd
1366
* boolean indicates whether the high nibble of <code>opDecimal[opEnd]</code> should be checked that it
1367
* contains a zero. If false, opEnd will be decremented and this will be the new starting point of the
1368
* algorithm which verifies that the remaining Packed Decimal digits are zeros.
1369
*
1370
* @return true if all digits from opOffset to opEnd are zero, false otherwise
1371
*
1372
* @throws ArrayIndexOutOfBoundsException
1373
* if an invalid array access occurs
1374
*/
1375
private static boolean checkZeroBetweenOpOffsetAndOpEnd(byte[] opDecimal, int opOffset, int opEnd, boolean opIsEven, boolean checkHighNibbleAtOpEnd) {
1376
if (checkHighNibbleAtOpEnd && (opDecimal[opEnd] & CommonData.HIGHER_NIBBLE_MASK) != 0x00)
1377
return false;
1378
1379
if (opEnd-- > opOffset) {
1380
// Handle intermediate bytes
1381
while (opEnd > opOffset) {
1382
if (opDecimal[opEnd--] != 0x00)
1383
return false;
1384
}
1385
1386
// Handle the most significant nibble/byte
1387
if (opIsEven) {
1388
if ((opDecimal[opEnd] & CommonData.LOWER_NIBBLE_MASK) != 0x00)
1389
return false;
1390
} else {
1391
if (opDecimal[opEnd] != 0x00)
1392
return false;
1393
}
1394
}
1395
1396
return true;
1397
}
1398
1399
1400
/**
1401
* Checks if the two Packed Decimal operands are unequal.
1402
*
1403
* @param op1Decimal
1404
* byte array that holds the first Packed Decimal operand
1405
* @param op1Offset
1406
* offset into <code>op1Decimal</code> where the first operand is located
1407
* @param op1Precision
1408
* number of Packed Decimal digits for the first operand
1409
* @param op2Decimal
1410
* byte array that holds the second Packed Decimal operand
1411
* @param op2Offset
1412
* offset into <code>op2Decimal</code> where the second operand is located
1413
* @param op2Precision
1414
* number of Packed Decimal digits for the second operand
1415
*
1416
* @return true if op1Decimal != op2Decimal, false otherwise
1417
*
1418
* @throws NullPointerException
1419
* if any of the byte arrays are null
1420
* @throws ArrayIndexOutOfBoundsException
1421
* if an invalid array access occurs
1422
*/
1423
public static boolean notEqualsPackedDecimal(byte[] op1Decimal,
1424
int op1Offset, int op1Precision, byte[] op2Decimal, int op2Offset,
1425
int op2Precision) {
1426
if ((op1Offset + ((op1Precision / 2) + 1) > op1Decimal.length) || (op1Offset < 0))
1427
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1428
"notEqualsPackedDecimal is trying to access op1Decimal[" + op1Offset + "] to op1Decimal[" + (op1Offset + (op1Precision / 2)) + "]" +
1429
" but valid indices are from 0 to " + (op1Decimal.length - 1) + ".");
1430
1431
if ((op2Offset < 0) || (op2Offset + ((op2Precision / 2) + 1) > op2Decimal.length))
1432
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1433
"notEqualsPackedDecimal is trying to access op2Decimal[" + op2Offset + "] to op2Decimal[" + (op2Offset + (op2Precision / 2)) + "]" +
1434
" but valid indices are from 0 to " + (op2Decimal.length - 1) + ".");
1435
1436
return notEqualsPackedDecimal_(op1Decimal, op1Offset, op1Precision,
1437
op2Decimal, op2Offset, op2Precision);
1438
}
1439
1440
private static boolean notEqualsPackedDecimal_(byte[] op1Decimal,
1441
int op1Offset, int op1Precision, byte[] op2Decimal, int op2Offset,
1442
int op2Precision) {
1443
return !equalsPackedDecimal(op1Decimal, op1Offset, op1Precision,
1444
op2Decimal, op2Offset, op2Precision);
1445
}
1446
1447
private static void roundUpPackedDecimal(byte[] packedDecimal, int offset,
1448
int end, int precision, int roundingDigit, boolean checkOverflow) {
1449
1450
packedDecimal[end] = CommonData.getPackedAddOneSignValues(packedDecimal[end]);
1451
1452
if ((byte) (packedDecimal[end] & CommonData.HIGHER_NIBBLE_MASK) == (byte) 0x00)
1453
{
1454
byte[] addTenArray = { 0x01, packedDecimal[end] };
1455
addPackedDecimal(packedDecimal, offset, precision,
1456
packedDecimal, offset, precision, addTenArray, 0, 2,
1457
checkOverflow);
1458
}
1459
}
1460
1461
/**
1462
* In case of a shift operation, this method is called to ensure if the resulting value of the shift is
1463
* zero that it is converted to a positive zero, meaning {0x....0C}. This is done to match the expected
1464
* result in COBOL.
1465
*/
1466
private static void checkIfZero(byte[] packedDecimal, int offset, int end, int precision, boolean isEvenPrecision) {
1467
1468
if (CommonData.getSign(packedDecimal[end] & CommonData.LOWER_NIBBLE_MASK) != CommonData.PACKED_MINUS)
1469
return;
1470
if (isEvenPrecision && ((packedDecimal[offset] & CommonData.LOWER_NIBBLE_MASK) != 0x00))
1471
return;
1472
//else if (packedDecimal[offset] != 0x00)
1473
// return;
1474
int i = offset;// + 1;
1475
for (; i < end && packedDecimal[i] == 0x00; i++) ;
1476
if (i < end)
1477
return;
1478
else if ((packedDecimal[end] & CommonData.HIGHER_NIBBLE_MASK) == 0x00)
1479
packedDecimal[end] = CommonData.PACKED_PLUS;
1480
1481
return;
1482
}
1483
1484
/**
1485
* Right shift, and optionally round, a Packed Decimal. If the resultant is zero,
1486
* it can either be a positive zero 0x0C or a negative zero 0x0D.
1487
*
1488
* @param destination
1489
* byte array that holds the result of the right shift (and rounding)
1490
* @param destinationOffset
1491
* offset into <code>destination</code> where the result Packed Decimal is located
1492
* @param destinationPrecision
1493
* number of Packed Decimal digits in the destination
1494
* @param source
1495
* byte array that holds the Packed Decimal operand to be right shifted
1496
* @param sourceOffset
1497
* offset into <code>source</code> where the operand is located
1498
* @param sourcePrecision
1499
* number of Packed Decimal digits in the operand
1500
* @param shiftAmount
1501
* amount by which the source will be right shifted
1502
* @param round
1503
* if set to true, causes rounding to occur
1504
* @param checkOverflow
1505
* if set to true, check for overflow
1506
*
1507
* @throws NullPointerException
1508
* if any of the byte arrays are null
1509
* @throws ArrayIndexOutOfBoundsException
1510
* if an invalid array access occurs
1511
* @throws ArithmeticException
1512
* if a decimal overflow occurs
1513
* @throws IllegalArgumentException
1514
* if the <code>shiftAmount</code> or <code>sourcePrecision</code> parameter is invalid or
1515
* the <code>source</code> packed decimal contains invalid sign or digit code
1516
*/
1517
public static void shiftRightPackedDecimal(byte[] destination,
1518
int destinationOffset, int destinationPrecision, byte[] source,
1519
int sourceOffset, int sourcePrecision, int shiftAmount,
1520
boolean round, boolean checkOverflow) {
1521
1522
if ((destinationOffset + ((destinationPrecision / 2) + 1) > destination.length) || (destinationOffset < 0))
1523
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1524
"shiftRightPackedDecimal is trying to access destinationDecimal[" + destinationOffset + "] to destinationDecimal[" + (destinationOffset + (destinationPrecision / 2)) + "]" +
1525
" but valid indices are from 0 to " + (destination.length - 1) + ".");
1526
1527
if ((sourceOffset < 0) || (sourceOffset + ((sourcePrecision / 2) + 1) > source.length))
1528
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1529
"shiftRightPackedDecimal is trying to access sourceDecimal[" + sourceOffset + "] to sourceDecimal[" + (sourceOffset + (sourcePrecision / 2)) + "]" +
1530
" but valid indices are from 0 to " + (source.length - 1) + ".");
1531
1532
shiftRightPackedDecimal_(destination, destinationOffset, destinationPrecision,
1533
source, sourceOffset, sourcePrecision, shiftAmount,
1534
round, checkOverflow);
1535
}
1536
1537
private static void shiftRightPackedDecimal_(byte[] destination,
1538
int destinationOffset, int destinationPrecision, byte[] source,
1539
int sourceOffset, int sourcePrecision, int shiftAmount,
1540
boolean round, boolean checkOverflow) {
1541
1542
// Figure out the sign of the source Packed Decimal
1543
int end = sourceOffset + precisionToByteLength(sourcePrecision) - 1;
1544
byte sign = CommonData.getSign(source[end] & CommonData.LOWER_NIBBLE_MASK);
1545
int newDstOffset = destinationOffset;
1546
int newDstPrec = destinationPrecision;
1547
int dstEnd = destinationOffset
1548
+ precisionToByteLength(destinationPrecision) - 1;
1549
int highDigit = sourcePrecision - 1;
1550
int lowDigit = 0;
1551
int precDiff = sourcePrecision - destinationPrecision;
1552
;
1553
int newSrcOffset;
1554
int newSrcEnd;
1555
boolean evenPrecision = sourcePrecision % 2 == 0;
1556
boolean isLeastSigDigitInHighNibble = false;
1557
boolean isMostSigDigitInLowNibble = false;
1558
int roundingDigit = 0;
1559
boolean overRanPD = false; // when the shifting left no digits to copy
1560
1561
if (destinationPrecision < 1 || sourcePrecision < 1 || shiftAmount < 0) {
1562
throw new IllegalArgumentException(
1563
"Invalid Precisions or shift amount");
1564
}
1565
1566
if(checkPackedDecimal_(source, sourceOffset, sourcePrecision, true, false) != 0) {
1567
throw new IllegalArgumentException(
1568
"Invalid sign or digit code in input packed decimal");
1569
}
1570
1571
lowDigit += shiftAmount;
1572
precDiff -= shiftAmount; // every time we shift, we lose precision
1573
if (precDiff > 0) // if we still need to lose some precision, take off
1574
// higher digits
1575
{
1576
highDigit -= precDiff;
1577
if (checkOverflow) {
1578
int bytes;
1579
int iter = 0;
1580
if (evenPrecision) {
1581
precDiff--;
1582
iter++;
1583
if ((byte) (source[sourceOffset] & CommonData.LOWER_NIBBLE_MASK) != 0x00)
1584
throw new ArithmeticException(
1585
"Decimal overflow in shiftRightPackedDecimal.");
1586
}
1587
bytes = (precDiff) / 2;
1588
precDiff -= bytes * 2;
1589
1590
for (int i = 0; i < bytes; i++) {
1591
if (source[i + sourceOffset + iter] != 0x00)
1592
throw new ArithmeticException(
1593
"Decimal overflow in shiftRightPackedDecimal.");
1594
}
1595
1596
if (precDiff == 1
1597
&& (byte) (source[bytes + sourceOffset] & CommonData.HIGHER_NIBBLE_MASK) != 0x00)
1598
throw new ArithmeticException(
1599
"Decimal overflow in shiftRightPackedDecimal.");
1600
1601
}
1602
}
1603
// add zeros if precDiff < 0, do this at end
1604
int newDifference = (highDigit + 1) - lowDigit; // might want to deal
1605
// with diff = 1
1606
if (checkOverflow && newDifference < 1)
1607
overRanPD = true;
1608
int highDiff = sourcePrecision - (highDigit + 1);
1609
1610
if (evenPrecision && newDifference % 2 == 0) // still even
1611
{
1612
if (highDiff % 2 == 0) // both low and high moved even
1613
{
1614
isMostSigDigitInLowNibble = true; // the highest digit is on a
1615
// low nibble
1616
isLeastSigDigitInHighNibble = true; // the lowest digit is on a
1617
// high nibble
1618
newSrcOffset = sourceOffset + (highDiff) / 2;
1619
newSrcEnd = end - (lowDigit) / 2;
1620
} else // high moved odd, low moved odd
1621
{
1622
newSrcOffset = sourceOffset + (highDiff + 1) / 2;
1623
newSrcEnd = end - (lowDigit + 1) / 2;
1624
}
1625
} else if (evenPrecision && newDifference % 2 != 0) {
1626
if (highDiff % 2 != 0) // high moved odd, low moved even
1627
{
1628
isLeastSigDigitInHighNibble = true;
1629
newSrcOffset = sourceOffset + (highDiff + 1) / 2;
1630
newSrcEnd = end - (lowDigit) / 2;
1631
} else // high moved even, low moved odd, perfect scenario
1632
{
1633
isMostSigDigitInLowNibble = true;
1634
newSrcOffset = sourceOffset + (highDiff) / 2;
1635
newSrcEnd = end - (lowDigit + 1) / 2;
1636
}
1637
} else if (!evenPrecision && newDifference % 2 == 0) {
1638
if (highDiff % 2 == 0) // high moved even, low moved odd
1639
{
1640
newSrcOffset = sourceOffset + (highDiff) / 2;
1641
newSrcEnd = end - (lowDigit + 1) / 2;
1642
} else // high moved odd, low moved even
1643
{
1644
isMostSigDigitInLowNibble = true; // get this high nibble
1645
// individually
1646
isLeastSigDigitInHighNibble = true; // get this lower nibble
1647
// individually
1648
newSrcOffset = sourceOffset + (highDiff) / 2;
1649
newSrcEnd = end - (lowDigit) / 2;
1650
}
1651
} else {
1652
if (highDiff % 2 == 0) // both moved even, perfect scenario
1653
{
1654
isLeastSigDigitInHighNibble = true;
1655
newSrcOffset = sourceOffset + (highDiff) / 2;
1656
newSrcEnd = end - (lowDigit) / 2;
1657
} else // both moved odd
1658
{
1659
isMostSigDigitInLowNibble = true;
1660
newSrcOffset = sourceOffset + (highDiff) / 2;
1661
newSrcEnd = end - (lowDigit + 1) / 2;
1662
}
1663
}
1664
1665
// find rounding digit
1666
if (round && shiftAmount > 0 && newDifference > -1) {
1667
if (isLeastSigDigitInHighNibble)
1668
roundingDigit = (source[newSrcEnd])
1669
& CommonData.LOWER_NIBBLE_MASK;
1670
else
1671
roundingDigit = (source[newSrcEnd + 1] >> 4)
1672
& CommonData.LOWER_NIBBLE_MASK;
1673
;
1674
}
1675
1676
while (precDiff < 0) // deal with dst prec being higher, put leading
1677
// zeros
1678
{
1679
destination[newDstOffset] = 0x00;
1680
if (newDstPrec % 2 == 0 || precDiff == -1) {
1681
if (newDstPrec % 2 == 0)
1682
newDstOffset++;
1683
precDiff++;
1684
newDstPrec--;
1685
1686
} else if ((precDiff / -2) >= 1) {
1687
precDiff += 2;
1688
newDstPrec -= 2;
1689
newDstOffset++;
1690
}
1691
}
1692
1693
if (isLeastSigDigitInHighNibble && !overRanPD) // can do arrayCopy,
1694
// instead of individual
1695
// nibbles
1696
{
1697
if (!isMostSigDigitInLowNibble) // just a simple arrayCopy
1698
System.arraycopy(source, newSrcOffset, destination,
1699
newDstOffset, newSrcEnd - newSrcOffset + 1);
1700
else {
1701
destination[newDstOffset] = (byte) ((source[newSrcOffset] & CommonData.LOWER_NIBBLE_MASK));
1702
newDstOffset++;
1703
newSrcOffset++;
1704
System.arraycopy(source, newSrcOffset, destination,
1705
newDstOffset, newSrcEnd - newSrcOffset + 1);
1706
}
1707
} else if (!overRanPD) // must copy each nibble over
1708
{
1709
int newDstEnd = newDstOffset + precisionToByteLength(newDstPrec)
1710
- 1;
1711
byte shiftByte = newSrcEnd < sourceOffset ? 0x00 : source[newSrcEnd];
1712
destination[newDstEnd] = (byte) ((shiftByte << 4) & CommonData.HIGHER_NIBBLE_MASK);
1713
newDstEnd--;
1714
newDstPrec--;
1715
byte current_nibble = 0;
1716
while ((newSrcEnd > newSrcOffset) && (newDstEnd > newDstOffset)) {
1717
current_nibble = (byte) ((source[newSrcEnd] >> 4) & CommonData.LOWER_NIBBLE_MASK);
1718
newSrcEnd--;
1719
current_nibble |= (byte) ((source[newSrcEnd] << 4) & CommonData.HIGHER_NIBBLE_MASK);
1720
destination[newDstEnd] = current_nibble;
1721
newDstEnd--;
1722
newDstPrec -= 2;
1723
}
1724
if (newDstPrec > 0) {
1725
destination[newDstEnd] = (byte) ((source[newSrcEnd] >> 4) & CommonData.LOWER_NIBBLE_MASK);
1726
newSrcEnd--;
1727
newDstPrec--;
1728
if (newDstPrec > 0 && isMostSigDigitInLowNibble)
1729
destination[newDstEnd] |= (byte) ((source[newSrcEnd] << 4) & CommonData.HIGHER_NIBBLE_MASK);
1730
}
1731
}
1732
// sign assignment
1733
if(overRanPD && roundingDigit < 5 && sign != CommonData.PACKED_PLUS)
1734
destination[dstEnd] = (byte) ((destination[dstEnd] & CommonData.HIGHER_NIBBLE_MASK) | sign);
1735
else
1736
{
1737
destination[dstEnd] = (byte) ((destination[dstEnd] & CommonData.HIGHER_NIBBLE_MASK) | (sign));
1738
if (round && roundingDigit >= 5)
1739
roundUpPackedDecimal(destination, destinationOffset, dstEnd,
1740
destinationPrecision, roundingDigit, checkOverflow);
1741
if (checkOverflow || round)
1742
checkIfZero(destination, destinationOffset, dstEnd, destinationPrecision, (destinationPrecision % 2 == 0 ? true : false));
1743
1744
}
1745
}
1746
1747
/**
1748
* Left shift a Packed Decimal appending zeros to the right. In the absence of overflow, the sign
1749
* of a zero can either be positive 0x0C or negative 0x0D.
1750
*
1751
* @param destination
1752
* byte array that holds the result of the left shift
1753
* @param destinationOffset
1754
* offset into <code>destination</code> where the result Packed Decimal is located
1755
* @param destinationPrecision
1756
* number of Packed Decimal digits in the destination
1757
* @param source
1758
* byte array that holds the Packed Decimal operand to be left shifted
1759
* @param sourceOffset
1760
* offset into <code>source</code> where the operand is located
1761
* @param sourcePrecision
1762
* number of Packed Decimal digits in the operand
1763
* @param shiftAmount
1764
* amount by which the source will be left shifted
1765
* @param checkOverflow
1766
* if set to true, check for overflow
1767
*
1768
* @throws NullPointerException
1769
* if any of the byte arrays are null
1770
* @throws ArrayIndexOutOfBoundsException
1771
* if an invalid array access occurs
1772
* @throws ArithmeticException
1773
* if a decimal overflow occurs
1774
* @throws IllegalArgumentException
1775
* if the <code>shiftAmount</code> or <code>sourcePrecision</code> parameter is invalid or
1776
* the <code>source</code> packed decimal contains invalid sign or digit code
1777
*/
1778
public static void shiftLeftPackedDecimal(byte[] destination,
1779
int destinationOffset, int destinationPrecision, byte[] source,
1780
int sourceOffset, int sourcePrecision, int shiftAmount,
1781
boolean checkOverflow) {
1782
if ((destinationOffset + ((destinationPrecision / 2) + 1) > destination.length) || (destinationOffset < 0))
1783
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1784
"shiftLeftPackedDecimal is trying to access destinationDecimal[" + destinationOffset + "] to destinationDecimal[" + (destinationOffset + (destinationPrecision / 2)) + "]" +
1785
" but valid indices are from 0 to " + (destination.length - 1) + ".");
1786
1787
if ((sourceOffset < 0) || (sourceOffset + ((sourcePrecision / 2) + 1) > source.length))
1788
throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +
1789
"shiftLeftPackedDecimal is trying to access sourceDecimal[" + sourceOffset + "] to sourceDecimal[" + (sourceOffset + (sourcePrecision / 2)) + "]" +
1790
" but valid indices are from 0 to " + (source.length - 1) + ".");
1791
1792
shiftLeftPackedDecimal_(destination, destinationOffset, destinationPrecision,
1793
source, sourceOffset, sourcePrecision, shiftAmount,
1794
checkOverflow);
1795
}
1796
1797
private static void shiftLeftPackedDecimal_(byte[] destination,
1798
int destinationOffset, int destinationPrecision, byte[] source,
1799
int sourceOffset, int sourcePrecision, int shiftAmount,
1800
boolean checkOverflow) {
1801
1802
if (destinationPrecision < 1 || sourcePrecision < 1 || shiftAmount < 0) {
1803
throw new IllegalArgumentException(
1804
"Invalid Precisions or shift amount");
1805
}
1806
1807
if(checkPackedDecimal_(source, sourceOffset, sourcePrecision, true, false) != 0) {
1808
throw new IllegalArgumentException(
1809
"Invalid sign or digit code in input packed decimal");
1810
}
1811
// Figure out the sign of the source Packed Decimal
1812
int end = sourceOffset + precisionToByteLength(sourcePrecision) - 1;
1813
byte sign = CommonData.getSign(source[end] & CommonData.LOWER_NIBBLE_MASK);
1814
boolean overRanPD = false;
1815
int sourceLength = precisionToByteLength(sourcePrecision);
1816
int destinationLength = precisionToByteLength(destinationPrecision);
1817
int shiftByte = shiftAmount / 2;
1818
int zerosBytesAtFront = 0;
1819
int totalZeros = 0;
1820
1821
// odd Precision
1822
if (sourcePrecision % 2 != 0) {
1823
1824
// Figure out how many 0x00s are at the front starting from the
1825
// offset
1826
for (zerosBytesAtFront = 0; zerosBytesAtFront < sourceLength; zerosBytesAtFront++) {
1827
if (source[zerosBytesAtFront + sourceOffset] != 0x00)
1828
break;
1829
}
1830
1831
// Figure out if 0x0*
1832
if ((byte) (source[zerosBytesAtFront + sourceOffset] & CommonData.HIGHER_NIBBLE_MASK) == 0x00)
1833
totalZeros++;
1834
1835
}// even precision
1836
else {
1837
// Figure out if bottom nibble of offset is 0 if it is then count
1838
// how many zero bytes there are at the front
1839
if ((byte) (source[sourceOffset] & CommonData.LOWER_NIBBLE_MASK) == 0x00) {
1840
totalZeros++;
1841
for (int i = 1; i < sourceLength; i++) {
1842
if (source[i + sourceOffset] != 0x00)
1843
break;
1844
else
1845
zerosBytesAtFront++;
1846
}
1847
if ((byte) (source[zerosBytesAtFront + sourceOffset + 1] & CommonData.HIGHER_NIBBLE_MASK) == 0x00)
1848
totalZeros++;
1849
}
1850
}
1851
// Add up all the zeros
1852
totalZeros += zerosBytesAtFront * 2;
1853
1854
// Check for overflow
1855
if (checkOverflow
1856
&& ((destinationPrecision + totalZeros < sourcePrecision
1857
+ shiftAmount)))
1858
throw new ArithmeticException(
1859
"Overflow - Destination precision not enough to hold the result of the shift operation");
1860
1861
// Zero out destination array in range
1862
Arrays.fill(destination, destinationOffset, destinationOffset
1863
+ destinationLength, (byte) 0x00);
1864
1865
int startIndexSource = zerosBytesAtFront + sourceOffset;
1866
int diff = destinationLength - sourceLength;
1867
int startIndexDestination = destinationOffset + zerosBytesAtFront
1868
- shiftByte + diff;
1869
int numberLength = sourceLength - zerosBytesAtFront; // non-zeros digits
1870
// length in bytes
1871
int movedSignIndex = startIndexDestination + numberLength - 1; // where
1872
// the
1873
// moved
1874
// sign
1875
// is
1876
// displaced
1877
// to
1878
1879
// if all digits are completely shifted out do nothing
1880
if (destinationPrecision <= shiftAmount)
1881
{
1882
if (checkOverflow && sign != CommonData.PACKED_PLUS)
1883
overRanPD = true;
1884
}
1885
else
1886
{
1887
// Even shift, can move byte by byte
1888
if (shiftAmount % 2 == 0)
1889
{
1890
if (startIndexDestination < destinationOffset)
1891
{
1892
int difference = sourcePrecision - (destinationPrecision - shiftAmount);
1893
int sourceIndex;
1894
if (sourcePrecision % 2 == 0)
1895
sourceIndex = sourceOffset + ((difference + 1) / 2);
1896
else
1897
sourceIndex = sourceOffset + (difference / 2);
1898
1899
System.arraycopy(source, sourceIndex, destination, destinationOffset, destinationLength
1900
- (shiftAmount / 2));
1901
}
1902
else
1903
System.arraycopy(source, startIndexSource, destination,
1904
startIndexDestination, sourceLength - zerosBytesAtFront);
1905
1906
// Strip off moved sign
1907
if (movedSignIndex >= 0)
1908
destination[movedSignIndex] = (byte) (destination[movedSignIndex] & CommonData.HIGHER_NIBBLE_MASK);
1909
}
1910
else
1911
{
1912
byte top;
1913
byte bottom;
1914
1915
// Move each nibble by appropriate index
1916
for (int i = 0; i < numberLength; i++) {
1917
top = (byte) (source[startIndexSource + i] & CommonData.HIGHER_NIBBLE_MASK);
1918
bottom = (byte) (source[startIndexSource + i] & CommonData.LOWER_NIBBLE_MASK);
1919
1920
if (startIndexDestination - 1 + i >= destinationOffset) {
1921
destination[startIndexDestination - 1 + i] = (byte) ((top >> 4 & CommonData.LOWER_NIBBLE_MASK) | (byte) (destination[startIndexDestination
1922
- 1 + i] & CommonData.HIGHER_NIBBLE_MASK));
1923
}
1924
if (startIndexDestination + i >= destinationOffset) {
1925
destination[startIndexDestination + i] = (byte) (bottom << 4);
1926
}
1927
1928
}
1929
// Strip off moved sign
1930
if (movedSignIndex >= 0)
1931
destination[movedSignIndex] = CommonData.PACKED_ZERO;
1932
}
1933
}
1934
int destinationEnd = destinationOffset + destinationLength - 1;
1935
boolean isDestionationEvenPrecision = destinationPrecision % 2 == 0 ? true : false;
1936
// Mask top Nibble
1937
if (isDestionationEvenPrecision)
1938
destination[destinationOffset] = (byte) (destination[destinationOffset] & CommonData.LOWER_NIBBLE_MASK);
1939
// Put sign in proper position
1940
1941
if (overRanPD)
1942
destination[destinationEnd] = (byte) (CommonData.PACKED_PLUS | destination[destinationEnd]);
1943
else
1944
{
1945
destination[destinationEnd] = (byte) (sign | destination[destinationEnd]);
1946
//checkOverflow will generate pdshlOverflow, which will cause it to reset sign. pdshl will not
1947
if (checkOverflow)
1948
checkIfZero(destination, destinationOffset, destinationEnd, destinationPrecision, isDestionationEvenPrecision);
1949
}
1950
}
1951
1952
/**
1953
* Creates a copy of a Packed Decimal.
1954
*
1955
* @param destination
1956
* byte array representing the destination
1957
* @param destinationOffset
1958
* offset into destination <code>destination</code> where the Packed Decimal is located
1959
* @param destinationPrecision
1960
* number of Packed Decimal digits for the destination
1961
* @param source
1962
* byte array which holds the source Packed Decimal
1963
* @param sourceOffset
1964
* offset into <code>source</code> where the Packed Decimal is located
1965
* @param sourcePrecision
1966
* number of Packed Decimal digits for the source. Maximum valid precision is 253
1967
* @param checkOverflow
1968
* if set to true, moved Packed Decimals are validated, and an <code>IllegalArgumentException</code> or
1969
* <code>ArithmeticException</code> is thrown if non-zero nibbles are truncated during the move
1970
* operation. If set to false, no validating is conducted.
1971
*
1972
* @throws NullPointerException
1973
* if any of the byte arrays are null
1974
* @throws ArrayIndexOutOfBoundsException
1975
* if an invalid array access occurs
1976
* @throws IllegalArgumentException
1977
* if the source Packed Decimal is invalid
1978
* @throws ArithmeticException
1979
* if a decimal overflow occurs
1980
*/
1981
public static void movePackedDecimal(byte[] destination,
1982
int destinationOffset, int destinationPrecision, byte[] source,
1983
int sourceOffset, int sourcePrecision, boolean checkOverflow) {
1984
shiftLeftPackedDecimal(destination, destinationOffset,
1985
destinationPrecision, source, sourceOffset,
1986
sourcePrecision, 0, checkOverflow);
1987
1988
}
1989
1990
private static class PackedDecimalOperand {
1991
1992
PackedDecimalOperand() {
1993
super();
1994
}
1995
1996
private static final byte PACKED_ZERO = 0x00;
1997
1998
byte[] byteArray;
1999
int offset;
2000
int precision;
2001
int bytes;
2002
int signOffset;
2003
int currentOffset;
2004
int signByteValue;
2005
int sign;
2006
int signDigit;
2007
int byteValue;
2008
int indexValue;
2009
2010
/**
2011
* Sets up the attributes of a Packed Decimal operand. Truncates leading zeros. Captures the sign value.
2012
*
2013
* @param byteArray
2014
* byte array which holds the Packed Decimal
2015
* @param offset
2016
* offset in <code>byteArray</code> where the Packed Decimal begins
2017
* @param precision
2018
* number of Packed Decimal digits. Maximum valid precision is 253
2019
*
2020
* @throws NullPointerException
2021
* if <code>byteArray</code> is null
2022
* @throws ArrayIndexOutOfBounds
2023
* if an invalid array access occurs
2024
*/
2025
public void setOperand(byte[] byteArray, int offset, int precision) {
2026
2027
this.byteArray = byteArray;
2028
this.offset = offset;
2029
this.precision = precision;
2030
2031
// truncate leading zeros
2032
bytes = CommonData.getPackedByteCount(precision);
2033
signOffset = this.offset + bytes - 1;
2034
currentOffset = signOffset - 1;
2035
for (; byteArray[this.offset] == PACKED_ZERO
2036
&& this.offset < signOffset; this.offset++)
2037
;
2038
bytes = signOffset - this.offset + 1;
2039
2040
// capture sign values
2041
signByteValue = this.byteArray[signOffset]
2042
& CommonData.INTEGER_MASK;
2043
signDigit = signByteValue & CommonData.HIGHER_NIBBLE_MASK;
2044
sign = CommonData.getSign(signByteValue & CommonData.LOWER_NIBBLE_MASK);
2045
2046
}
2047
2048
/**
2049
* Sets up attributes of a Packed Decimal which is about to be the result operand holding the sum of two Packed
2050
* Decimal operands. Does not truncate leading zeroes. Does not capture the sign.
2051
*
2052
* @param byteArray
2053
* byte array which holds the Packed Decimal
2054
* @param offset
2055
* offset in <code>byteArray</code> where the Packed Decimal begins
2056
* @param precision
2057
* number of Packed Decimal digits. Maximum valid precision is 253
2058
*
2059
* @throws NullPointerException
2060
* if <code>byteArray</code> is null
2061
* @throws ArrayIndexOutOfBounds
2062
* if an invalid array access occurs
2063
*/
2064
public void setSumOperand(byte[] byteArray, int offset, int precision) {
2065
2066
this.byteArray = byteArray;
2067
this.offset = offset;
2068
this.precision = precision;
2069
2070
bytes = CommonData.getPackedByteCount(precision);
2071
signOffset = this.offset + bytes - 1;
2072
currentOffset = signOffset - 1;
2073
2074
}
2075
2076
}
2077
2078
}
2079
2080