KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > client > am > Decimal


1 /*
2
3    Derby - Class org.apache.derby.client.am.Decimal
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to You under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20 */

21 package org.apache.derby.client.am;
22
23 import org.apache.derby.shared.common.reference.SQLState;
24 import org.apache.derby.shared.common.i18n.MessageUtil;
25
26 /**
27  * Converters from fixed point decimal bytes to <code>java.math.BigDecimal</code>, <code>double</code>, or
28  * <code>long</code>.
29  */

30 public class Decimal {
31     /**
32      * Packed Decimal representation
33      */

34     public final static int PACKED_DECIMAL = 0x30;
35     
36     private static MessageUtil msgutil = SqlException.getMessageUtil();
37
38     //--------------------------private constants---------------------------------
39

40     private static final int[][] tenRadixMagnitude = {
41         {0x3b9aca00}, // 10^9
42
{0x0de0b6b3, 0xa7640000}, // 10^18
43
{0x033b2e3c, 0x9fd0803c, 0xe8000000}, // 10^27
44
};
45
46     //--------------------------constructors--------------------------------------
47

48     // Hide the default constructor, this is a static class.
49
private Decimal() {
50     }
51
52     //--------------------------private helper methods----------------------------
53

54     /**
55      * Convert a range of packed nybbles (up to 9 digits without overflow) to an int. Note that for performance purpose,
56      * it does not do array-out-of-bound checking.
57      */

58     private static final int packedNybblesToInt(byte[] buffer,
59                                                 int offset,
60                                                 int startNybble,
61                                                 int numberOfNybbles) {
62         int value = 0;
63
64         int i = startNybble / 2;
65         if ((startNybble % 2) != 0) {
66             // process low nybble of the first byte if necessary.
67
value += buffer[offset + i] & 0x0F;
68             i++;
69         }
70
71         int endNybble = startNybble + numberOfNybbles - 1;
72         for (; i < (endNybble + 1) / 2; i++) {
73             value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); // high nybble.
74
value = value * 10 + (buffer[offset + i] & 0x0F); // low nybble.
75
}
76
77         if ((endNybble % 2) == 0) {
78             // process high nybble of the last byte if necessary.
79
value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4);
80         }
81
82         return value;
83     }
84
85     /**
86      * Convert a range of packed nybbles (up to 18 digits without overflow) to a long. Note that for performance
87      * purpose, it does not do array-out-of-bound checking.
88      */

89     private static final long packedNybblesToLong(byte[] buffer,
90                                                   int offset,
91                                                   int startNybble,
92                                                   int numberOfNybbles) {
93         long value = 0;
94
95         int i = startNybble / 2;
96         if ((startNybble % 2) != 0) {
97             // process low nybble of the first byte if necessary.
98
value += buffer[offset + i] & 0x0F;
99             i++;
100         }
101
102         int endNybble = startNybble + numberOfNybbles - 1;
103         for (; i < (endNybble + 1) / 2; i++) {
104             value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); // high nybble.
105
value = value * 10 + (buffer[offset + i] & 0x0F); // low nybble.
106
}
107
108         if ((endNybble % 2) == 0) {
109             // process high nybble of the last byte if necessary.
110
value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4);
111         }
112
113         return value;
114     }
115
116     /**
117      * Compute the int array of magnitude from input value segments.
118      */

119     private static final int[] computeMagnitude(int[] input) {
120         int length = input.length;
121         int[] mag = new int[length];
122
123         mag[length - 1] = input[length - 1];
124         for (int i = 0; i < length - 1; i++) {
125             int carry = 0;
126             int j = tenRadixMagnitude[i].length - 1;
127             int k = length - 1;
128             for (; j >= 0; j--, k--) {
129                 long product = (input[length - 2 - i] & 0xFFFFFFFFL) * (tenRadixMagnitude[i][j] & 0xFFFFFFFFL)
130                         + (mag[k] & 0xFFFFFFFFL) // add previous value
131
+ (carry & 0xFFFFFFFFL); // add carry
132
carry = (int) (product >>> 32);
133                 mag[k] = (int) (product & 0xFFFFFFFFL);
134             }
135             mag[k] = (int) carry;
136         }
137         return mag;
138     }
139
140     //--------------entry points for runtime representation-----------------------
141

142     /**
143      * Build a <code>java.math.BigDecimal</code> from a fixed point decimal byte representation.
144      *
145      * @throws IllegalArgumentException if the specified representation is not recognized.
146      */

147     public static final java.math.BigDecimal JavaDoc getBigDecimal(byte[] buffer,
148                                                            int offset,
149                                                            int precision,
150                                                            int scale) throws java.io.UnsupportedEncodingException JavaDoc {
151         // The byte-length of a packed decimal with precision <code>p</code> is always <code>p/2 + 1</code>
152
int length = precision / 2 + 1;
153
154         // check for sign.
155
int signum;
156         if ((buffer[offset + length - 1] & 0x0F) == 0x0D) {
157             signum = -1;
158         } else {
159             signum = 1;
160         }
161
162         if (precision <= 9) {
163             // can be handled by int without overflow.
164
int value = packedNybblesToInt(buffer, offset, 0, length * 2 - 1);
165
166             // convert value to a byte array of magnitude.
167
byte[] magnitude = new byte[4];
168             magnitude[0] = (byte) (value >>> 24);
169             magnitude[1] = (byte) (value >>> 16);
170             magnitude[2] = (byte) (value >>> 8);
171             magnitude[3] = (byte) (value);
172
173             return new java.math.BigDecimal JavaDoc(new java.math.BigInteger JavaDoc(signum, magnitude), scale);
174         } else if (precision <= 18) {
175             // can be handled by long without overflow.
176
long value = packedNybblesToLong(buffer, offset, 0, length * 2 - 1);
177
178             // convert value to a byte array of magnitude.
179
byte[] magnitude = new byte[8];
180             magnitude[0] = (byte) (value >>> 56);
181             magnitude[1] = (byte) (value >>> 48);
182             magnitude[2] = (byte) (value >>> 40);
183             magnitude[3] = (byte) (value >>> 32);
184             magnitude[4] = (byte) (value >>> 24);
185             magnitude[5] = (byte) (value >>> 16);
186             magnitude[6] = (byte) (value >>> 8);
187             magnitude[7] = (byte) (value);
188
189             return new java.math.BigDecimal JavaDoc(new java.math.BigInteger JavaDoc(signum, magnitude), scale);
190         } else if (precision <= 27) {
191             // get the value of last 9 digits (5 bytes).
192
int lo = packedNybblesToInt(buffer, offset, (length - 5) * 2, 9);
193             // get the value of another 9 digits (5 bytes).
194
int me = packedNybblesToInt(buffer, offset, (length - 10) * 2 + 1, 9);
195             // get the value of the rest digits.
196
int hi = packedNybblesToInt(buffer, offset, 0, (length - 10) * 2 + 1);
197
198             // compute the int array of magnitude.
199
int[] value = computeMagnitude(new int[]{hi, me, lo});
200
201             // convert value to a byte array of magnitude.
202
byte[] magnitude = new byte[12];
203             magnitude[0] = (byte) (value[0] >>> 24);
204             magnitude[1] = (byte) (value[0] >>> 16);
205             magnitude[2] = (byte) (value[0] >>> 8);
206             magnitude[3] = (byte) (value[0]);
207             magnitude[4] = (byte) (value[1] >>> 24);
208             magnitude[5] = (byte) (value[1] >>> 16);
209             magnitude[6] = (byte) (value[1] >>> 8);
210             magnitude[7] = (byte) (value[1]);
211             magnitude[8] = (byte) (value[2] >>> 24);
212             magnitude[9] = (byte) (value[2] >>> 16);
213             magnitude[10] = (byte) (value[2] >>> 8);
214             magnitude[11] = (byte) (value[2]);
215
216             return new java.math.BigDecimal JavaDoc(new java.math.BigInteger JavaDoc(signum, magnitude), scale);
217         } else if (precision <= 31) {
218             // get the value of last 9 digits (5 bytes).
219
int lo = packedNybblesToInt(buffer, offset, (length - 5) * 2, 9);
220             // get the value of another 9 digits (5 bytes).
221
int meLo = packedNybblesToInt(buffer, offset, (length - 10) * 2 + 1, 9);
222             // get the value of another 9 digits (5 bytes).
223
int meHi = packedNybblesToInt(buffer, offset, (length - 14) * 2, 9);
224             // get the value of the rest digits.
225
int hi = packedNybblesToInt(buffer, offset, 0, (length - 14) * 2);
226
227             // compute the int array of magnitude.
228
int[] value = computeMagnitude(new int[]{hi, meHi, meLo, lo});
229
230             // convert value to a byte array of magnitude.
231
byte[] magnitude = new byte[16];
232             magnitude[0] = (byte) (value[0] >>> 24);
233             magnitude[1] = (byte) (value[0] >>> 16);
234             magnitude[2] = (byte) (value[0] >>> 8);
235             magnitude[3] = (byte) (value[0]);
236             magnitude[4] = (byte) (value[1] >>> 24);
237             magnitude[5] = (byte) (value[1] >>> 16);
238             magnitude[6] = (byte) (value[1] >>> 8);
239             magnitude[7] = (byte) (value[1]);
240             magnitude[8] = (byte) (value[2] >>> 24);
241             magnitude[9] = (byte) (value[2] >>> 16);
242             magnitude[10] = (byte) (value[2] >>> 8);
243             magnitude[11] = (byte) (value[2]);
244             magnitude[12] = (byte) (value[3] >>> 24);
245             magnitude[13] = (byte) (value[3] >>> 16);
246             magnitude[14] = (byte) (value[3] >>> 8);
247             magnitude[15] = (byte) (value[3]);
248
249             return new java.math.BigDecimal JavaDoc(new java.math.BigInteger JavaDoc(signum, magnitude), scale);
250         } else {
251             // throw an exception here if nibbles is greater than 31
252
throw new java.lang.IllegalArgumentException JavaDoc(
253                 msgutil.getTextMessage(SQLState.DECIMAL_TOO_MANY_DIGITS));
254         }
255     }
256
257     /**
258      * Build a Java <code>double</code> from a fixed point decimal byte representation.
259      *
260      * @throws IllegalArgumentException if the specified representation is not recognized.
261      */

262     public static final double getDouble(byte[] buffer,
263                                          int offset,
264                                          int precision,
265                                          int scale) throws java.io.UnsupportedEncodingException JavaDoc {
266         // The byte-length of a packed decimal with precision <code>p</code> is always <code>p/2 + 1</code>
267
int length = precision / 2 + 1;
268
269         // check for sign.
270
int signum;
271         if ((buffer[offset + length - 1] & 0x0F) == 0x0D) {
272             signum = -1;
273         } else {
274             signum = 1;
275         }
276
277         if (precision <= 9) {
278             // can be handled by int without overflow.
279
int value = packedNybblesToInt(buffer, offset, 0, length * 2 - 1);
280
281             return signum * value / Math.pow(10, scale);
282         } else if (precision <= 18) {
283             // can be handled by long without overflow.
284
long value = packedNybblesToLong(buffer, offset, 0, length * 2 - 1);
285
286             return signum * value / Math.pow(10, scale);
287         } else if (precision <= 27) {
288             // get the value of last 9 digits (5 bytes).
289
int lo = packedNybblesToInt(buffer, offset, (length - 5) * 2, 9);
290             // get the value of another 9 digits (5 bytes).
291
int me = packedNybblesToInt(buffer, offset, (length - 10) * 2 + 1, 9);
292             // get the value of the rest digits.
293
int hi = packedNybblesToInt(buffer, offset, 0, (length - 10) * 2 + 1);
294
295             return signum * (lo / Math.pow(10, scale) +
296                     me * Math.pow(10, 9 - scale) +
297                     hi * Math.pow(10, 18 - scale));
298         } else if (precision <= 31) {
299             // get the value of last 9 digits (5 bytes).
300
int lo = packedNybblesToInt(buffer, offset, (length - 5) * 2, 9);
301             // get the value of another 9 digits (5 bytes).
302
int meLo = packedNybblesToInt(buffer, offset, (length - 10) * 2 + 1, 9);
303             // get the value of another 9 digits (5 bytes).
304
int meHi = packedNybblesToInt(buffer, offset, (length - 14) * 2, 9);
305             // get the value of the rest digits.
306
int hi = packedNybblesToInt(buffer, offset, 0, (length - 14) * 2);
307
308             return signum * (lo / Math.pow(10, scale) +
309                     meLo * Math.pow(10, 9 - scale) +
310                     meHi * Math.pow(10, 18 - scale) +
311                     hi * Math.pow(10, 27 - scale));
312         } else {
313             // throw an exception here if nibbles is greater than 31
314
throw new java.lang.IllegalArgumentException JavaDoc(
315                 msgutil.getTextMessage(SQLState.DECIMAL_TOO_MANY_DIGITS));
316         }
317     }
318
319     /**
320      * Build a Java <code>long</code> from a fixed point decimal byte representation.
321      *
322      * @throws IllegalArgumentException if the specified representation is not recognized.
323      */

324     public static final long getLong(byte[] buffer,
325                                      int offset,
326                                      int precision,
327                                      int scale) throws java.io.UnsupportedEncodingException JavaDoc {
328         if (precision > 31) {
329             // throw an exception here if nibbles is greater than 31
330
throw new java.lang.IllegalArgumentException JavaDoc(
331                 msgutil.getTextMessage(SQLState.DECIMAL_TOO_MANY_DIGITS));
332         }
333
334         // The byte-length of a packed decimal with precision <code>p</code> is always <code>p/2 + 1</code>
335
int length = precision / 2 + 1;
336
337         // check for sign.
338
int signum;
339         if ((buffer[offset + length - 1] & 0x0F) == 0x0D) {
340             signum = -1;
341         } else {
342             signum = 1;
343         }
344
345         // compute the integer part only.
346
int leftOfDecimalPoint = length * 2 - 1 - scale;
347         long integer = 0;
348         if (leftOfDecimalPoint > 0) {
349             int i = 0;
350             for (; i < leftOfDecimalPoint / 2; i++) {
351                 integer = integer * 10 + signum * ((buffer[offset + i] & 0xF0) >>> 4); // high nybble.
352
integer = integer * 10 + signum * (buffer[offset + i] & 0x0F); // low nybble.
353
}
354             if ((leftOfDecimalPoint % 2) == 1) {
355                 // process high nybble of the last byte if necessary.
356
integer = integer * 10 + signum * ((buffer[offset + i] & 0xF0) >>> 4);
357             }
358         }
359
360         return integer;
361     }
362
363     //--------------entry points for runtime representation-----------------------
364

365     /**
366      * Write a Java <code>java.math.BigDecimal</code> to packed decimal bytes.
367      */

368     public static final int bigDecimalToPackedDecimalBytes(byte[] buffer,
369                                                            int offset,
370                                                            java.math.BigDecimal JavaDoc b,
371                                                            int declaredPrecision,
372                                                            int declaredScale)
373             throws SqlException {
374         // packed decimal may only be up to 31 digits.
375
if (declaredPrecision > 31) {
376             throw new SqlException(null,
377                 new ClientMessageId(SQLState.DECIMAL_TOO_MANY_DIGITS));
378         }
379
380         // get absolute unscaled value of the BigDecimal as a String.
381
String JavaDoc unscaledStr = b.unscaledValue().abs().toString();
382
383         // get precision of the BigDecimal.
384
int bigPrecision = unscaledStr.length();
385
386         if (bigPrecision > 31) {
387             throw new SqlException(null,
388                 new ClientMessageId(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE),
389                 "packed decimal", new SqlCode(-405));
390         }
391
392         int bigScale = b.scale();
393         int bigWholeIntegerLength = bigPrecision - bigScale;
394         if ((bigWholeIntegerLength > 0) && (!unscaledStr.equals("0"))) {
395             // if whole integer part exists, check if overflow.
396
int declaredWholeIntegerLength = declaredPrecision - declaredScale;
397             if (bigWholeIntegerLength > declaredWholeIntegerLength) {
398                 throw new SqlException(null,
399                     new ClientMessageId(SQLState.NUMERIC_OVERFLOW),
400                     b.toString(), "packed decimal", new SqlCode(-413));
401             }
402         }
403
404         // convert the unscaled value to a packed decimal bytes.
405

406         // get unicode '0' value.
407
int zeroBase = '0';
408
409         // start index in target packed decimal.
410
int packedIndex = declaredPrecision - 1;
411
412         // start index in source big decimal.
413
int bigIndex;
414
415         if (bigScale >= declaredScale) {
416             // If target scale is less than source scale,
417
// discard excessive fraction.
418

419             // set start index in source big decimal to ignore excessive fraction.
420
bigIndex = bigPrecision - 1 - (bigScale - declaredScale);
421
422             if (bigIndex < 0) {
423                 // all digits are discarded, so only process the sign nybble.
424
buffer[offset + (packedIndex + 1) / 2] =
425                         (byte) ((b.signum() >= 0) ? 12 : 13); // sign nybble
426
} else {
427                 // process the last nybble together with the sign nybble.
428
buffer[offset + (packedIndex + 1) / 2] =
429                         (byte) (((unscaledStr.charAt(bigIndex) - zeroBase) << 4) + // last nybble
430
((b.signum() >= 0) ? 12 : 13)); // sign nybble
431
}
432             packedIndex -= 2;
433             bigIndex -= 2;
434         } else {
435             // If target scale is greater than source scale,
436
// pad the fraction with zero.
437

438             // set start index in source big decimal to pad fraction with zero.
439
bigIndex = declaredScale - bigScale - 1;
440
441             // process the sign nybble.
442
buffer[offset + (packedIndex + 1) / 2] =
443                     (byte) ((b.signum() >= 0) ? 12 : 13); // sign nybble
444

445             for (packedIndex -= 2, bigIndex -= 2; bigIndex >= 0; packedIndex -= 2, bigIndex -= 2) {
446                 buffer[offset + (packedIndex + 1) / 2] = (byte) 0;
447             }
448
449             if (bigIndex == -1) {
450                 buffer[offset + (packedIndex + 1) / 2] =
451                         (byte) ((unscaledStr.charAt(bigPrecision - 1) - zeroBase) << 4); // high nybble
452

453                 packedIndex -= 2;
454                 bigIndex = bigPrecision - 3;
455             } else {
456                 bigIndex = bigPrecision - 2;
457             }
458         }
459
460         // process the rest.
461
for (; bigIndex >= 0; packedIndex -= 2, bigIndex -= 2) {
462             buffer[offset + (packedIndex + 1) / 2] =
463                     (byte) (((unscaledStr.charAt(bigIndex) - zeroBase) << 4) + // high nybble
464
(unscaledStr.charAt(bigIndex + 1) - zeroBase)); // low nybble
465
}
466
467         // process the first nybble when there is one left.
468
if (bigIndex == -1) {
469             buffer[offset + (packedIndex + 1) / 2] =
470                     (byte) (unscaledStr.charAt(0) - zeroBase);
471
472             packedIndex -= 2;
473         }
474
475         // pad zero in front of the big decimal if necessary.
476
for (; packedIndex >= -1; packedIndex -= 2) {
477             buffer[offset + (packedIndex + 1) / 2] = (byte) 0;
478         }
479
480         return declaredPrecision / 2 + 1;
481     }
482 }
483
Popular Tags