📄 decimal.java
字号:
/* Derby - Class org.apache.derby.client.am.Decimal Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.*/package org.apache.derby.client.am;/** * Converters from fixed point decimal bytes to <code>java.math.BigDecimal</code>, <code>double</code>, or * <code>long</code>. */public class Decimal { /** * Packed Decimal representation */ public final static int PACKED_DECIMAL = 0x30; //--------------------------private constants--------------------------------- private static final int[][] tenRadixMagnitude = { {0x3b9aca00}, // 10^9 {0x0de0b6b3, 0xa7640000}, // 10^18 {0x033b2e3c, 0x9fd0803c, 0xe8000000}, // 10^27 }; //--------------------------constructors-------------------------------------- // Hide the default constructor, this is a static class. private Decimal() { } //--------------------------private helper methods---------------------------- /** * Convert a range of packed nybbles (up to 9 digits without overflow) to an int. Note that for performance purpose, * it does not do array-out-of-bound checking. */ private static final int packedNybblesToInt(byte[] buffer, int offset, int startNybble, int numberOfNybbles) { int value = 0; int i = startNybble / 2; if ((startNybble % 2) != 0) { // process low nybble of the first byte if necessary. value += buffer[offset + i] & 0x0F; i++; } int endNybble = startNybble + numberOfNybbles - 1; for (; i < (endNybble + 1) / 2; i++) { value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); // high nybble. value = value * 10 + (buffer[offset + i] & 0x0F); // low nybble. } if ((endNybble % 2) == 0) { // process high nybble of the last byte if necessary. value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); } return value; } /** * Convert a range of packed nybbles (up to 18 digits without overflow) to a long. Note that for performance * purpose, it does not do array-out-of-bound checking. */ private static final long packedNybblesToLong(byte[] buffer, int offset, int startNybble, int numberOfNybbles) { long value = 0; int i = startNybble / 2; if ((startNybble % 2) != 0) { // process low nybble of the first byte if necessary. value += buffer[offset + i] & 0x0F; i++; } int endNybble = startNybble + numberOfNybbles - 1; for (; i < (endNybble + 1) / 2; i++) { value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); // high nybble. value = value * 10 + (buffer[offset + i] & 0x0F); // low nybble. } if ((endNybble % 2) == 0) { // process high nybble of the last byte if necessary. value = value * 10 + ((buffer[offset + i] & 0xF0) >>> 4); } return value; } /** * Compute the int array of magnitude from input value segments. */ private static final int[] computeMagnitude(int[] input) { int length = input.length; int[] mag = new int[length]; mag[length - 1] = input[length - 1]; for (int i = 0; i < length - 1; i++) { int carry = 0; int j = tenRadixMagnitude[i].length - 1; int k = length - 1; for (; j >= 0; j--, k--) { long product = (input[length - 2 - i] & 0xFFFFFFFFL) * (tenRadixMagnitude[i][j] & 0xFFFFFFFFL) + (mag[k] & 0xFFFFFFFFL) // add previous value + (carry & 0xFFFFFFFFL); // add carry carry = (int) (product >>> 32); mag[k] = (int) (product & 0xFFFFFFFFL); } mag[k] = (int) carry; } return mag; } //--------------entry points for runtime representation----------------------- /** * Build a <code>java.math.BigDecimal</code> from a fixed point decimal byte representation. * * @throws IllegalArgumentException if the specified representation is not recognized. */ public static final java.math.BigDecimal getBigDecimal(byte[] buffer, int offset, int precision, int scale) throws java.io.UnsupportedEncodingException { // The byte-length of a packed decimal with precision <code>p</code> is always <code>p/2 + 1</code> int length = precision / 2 + 1; // check for sign. int signum; if ((buffer[offset + length - 1] & 0x0F) == 0x0D) { signum = -1; } else { signum = 1; } if (precision <= 9) { // can be handled by int without overflow. int value = packedNybblesToInt(buffer, offset, 0, length * 2 - 1); // convert value to a byte array of magnitude. byte[] magnitude = new byte[4]; magnitude[0] = (byte) (value >>> 24); magnitude[1] = (byte) (value >>> 16); magnitude[2] = (byte) (value >>> 8); magnitude[3] = (byte) (value); return new java.math.BigDecimal(new java.math.BigInteger(signum, magnitude), scale); } else if (precision <= 18) { // can be handled by long without overflow. long value = packedNybblesToLong(buffer, offset, 0, length * 2 - 1); // convert value to a byte array of magnitude. byte[] magnitude = new byte[8]; magnitude[0] = (byte) (value >>> 56); magnitude[1] = (byte) (value >>> 48); magnitude[2] = (byte) (value >>> 40); magnitude[3] = (byte) (value >>> 32); magnitude[4] = (byte) (value >>> 24); magnitude[5] = (byte) (value >>> 16); magnitude[6] = (byte) (value >>> 8); magnitude[7] = (byte) (value); return new java.math.BigDecimal(new java.math.BigInteger(signum, magnitude), scale); } else if (precision <= 27) { // get the value of last 9 digits (5 bytes). int lo = packedNybblesToInt(buffer, offset, (length - 5) * 2, 9); // get the value of another 9 digits (5 bytes). int me = packedNybblesToInt(buffer, offset, (length - 10) * 2 + 1, 9); // get the value of the rest digits. int hi = packedNybblesToInt(buffer, offset, 0, (length - 10) * 2 + 1); // compute the int array of magnitude. int[] value = computeMagnitude(new int[]{hi, me, lo}); // convert value to a byte array of magnitude. byte[] magnitude = new byte[12]; magnitude[0] = (byte) (value[0] >>> 24); magnitude[1] = (byte) (value[0] >>> 16); magnitude[2] = (byte) (value[0] >>> 8); magnitude[3] = (byte) (value[0]); magnitude[4] = (byte) (value[1] >>> 24); magnitude[5] = (byte) (value[1] >>> 16); magnitude[6] = (byte) (value[1] >>> 8); magnitude[7] = (byte) (value[1]); magnitude[8] = (byte) (value[2] >>> 24); magnitude[9] = (byte) (value[2] >>> 16); magnitude[10] = (byte) (value[2] >>> 8); magnitude[11] = (byte) (value[2]); return new java.math.BigDecimal(new java.math.BigInteger(signum, magnitude), scale); } else if (precision <= 31) { // get the value of last 9 digits (5 bytes). int lo = packedNybblesToInt(buffer, offset, (length - 5) * 2, 9); // get the value of another 9 digits (5 bytes). int meLo = packedNybblesToInt(buffer, offset, (length - 10) * 2 + 1, 9); // get the value of another 9 digits (5 bytes). int meHi = packedNybblesToInt(buffer, offset, (length - 14) * 2, 9); // get the value of the rest digits. int hi = packedNybblesToInt(buffer, offset, 0, (length - 14) * 2); // compute the int array of magnitude. int[] value = computeMagnitude(new int[]{hi, meHi, meLo, lo}); // convert value to a byte array of magnitude. byte[] magnitude = new byte[16]; magnitude[0] = (byte) (value[0] >>> 24); magnitude[1] = (byte) (value[0] >>> 16); magnitude[2] = (byte) (value[0] >>> 8); magnitude[3] = (byte) (value[0]); magnitude[4] = (byte) (value[1] >>> 24); magnitude[5] = (byte) (value[1] >>> 16); magnitude[6] = (byte) (value[1] >>> 8); magnitude[7] = (byte) (value[1]); magnitude[8] = (byte) (value[2] >>> 24); magnitude[9] = (byte) (value[2] >>> 16); magnitude[10] = (byte) (value[2] >>> 8); magnitude[11] = (byte) (value[2]); magnitude[12] = (byte) (value[3] >>> 24); magnitude[13] = (byte) (value[3] >>> 16);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -